TypeScript - 检查对象的 属性 是否是具有给定签名的函数
TypeScript - check if object's property is a function with given signature
我有一个从对象获取 属性 的函数。
// Utils.ts
export function getProperty<T, K extends keyof T>(obj: T, key: string): T[K] {
if (key in obj) { return obj[key as K]; }
throw new Error(`Invalid object member "${key}"`);
}
我想检查返回的 属性 是否是具有给定签名的函数,然后使用提供的参数调用 属性。
getProperty()
用于动态获取对象的方法之一并调用它。我试过了:
let property: this[keyof this] = utils.getProperty(this, name);
if (typeof property === 'function') ) { property(conf); }
但这会产生 "Cannot invoke an expression whose type lacks a call signature. Type 'any' has no compatible call signatures." 错误。我知道来自 getProperty()
的 属性 确实可以是任何类型,但是如何确定它是具有 (conf: {}): void
签名的函数?
在你的函数签名中有一个错误,key
参数应该是 K
类型,当你对参数使用常量时,这会给你更好的推断:
export function getProperty<T, K extends keyof T>(obj: T, key: string): T[K] {
if (key in obj) { return obj[key as K]; }
throw new Error(`Invalid object member "${key}"`);
}
let foo = {
fn (conf: {}): void {}
}
let fn = getProperty(foo, "fn");
fn({}); // callable
当您使用字符串形式且在编译时未验证的键时,问题是编译器无法真正帮助您解决任何问题。它将假定由于您索引了我的任意字符串,因此 return 类型可以是目标的任何有效字段类型。无法在运行时验证函数参数类型,因为它们将被删除,但您可以验证参数计数:
let property: Function = getProperty(this, name) as any;
if (typeof property === 'function' && property.length == 1)
{
property({});
}
它看起来不像 typeof
type guards exist for function types. It seems to be by design; see microsoft/TypeScript#2072(这个问题是关于 instanceof
类型保护的,但我猜这是类似的推理)。
但是,TypeScript 确实有 user-defined type guards,这意味着您可以编写一个函数,以任何您喜欢的方式缩小其参数的类型。
当代码编译为 JavaScript 时,TypeScript 的静态类型系统是 erased。在运行时,没有诸如 (conf: {}) => void
之类的东西可供您检查。如果您想编写运行时测试来区分类型 (conf: {}) => void
的值与其他类型的值,您将只能做到这一点。
你可以测试一下typeof x === "function"
。但这只是告诉你这是一个功能。它 不 表示函数有多少个参数以及它们的类型是什么。您还可以检查 if x.length === 1
以查看该函数是否需要一个参数,尽管在 Function.length
周围有涉及剩余参数和默认参数的注意事项。但现在你有点卡住了。
在运行时,任何关于函数参数 types 的信息都将被删除,如果这些函数最初来自 TypeScript 代码。您最多可以通过使用一些测试参数调用它并检查是否出现问题来“探测”该函数。但这是一个具有可能副作用的破坏性测试,并且违背了在调用函数之前检查函数类型是否正确的目的。
也许您不介意这个限制,并且假设 length
为 1
的函数是一个足够好的测试。或者也许你有一些其他的测试(例如,也许你可以添加一个名为 isOfRightType
的 属性 其值为 true
到你关心的所有这些函数,然后只测试那个 属性。这通过引入假阴性的可能性来消除假阳性)。一旦你知道你的运行时测试,你就可以做一个类型保护:
function isFunctionOfRightType(x: any): x is (conf: {})=>void {
return (typeof x === 'function') && (x.length === 1); // or whatever test
}
// ... later
let property: this[keyof this] = utils.getProperty(this, name);
if (isFunctionOfRightType(property)) { property(conf); } // no error now
我有一个从对象获取 属性 的函数。
// Utils.ts
export function getProperty<T, K extends keyof T>(obj: T, key: string): T[K] {
if (key in obj) { return obj[key as K]; }
throw new Error(`Invalid object member "${key}"`);
}
我想检查返回的 属性 是否是具有给定签名的函数,然后使用提供的参数调用 属性。
getProperty()
用于动态获取对象的方法之一并调用它。我试过了:
let property: this[keyof this] = utils.getProperty(this, name);
if (typeof property === 'function') ) { property(conf); }
但这会产生 "Cannot invoke an expression whose type lacks a call signature. Type 'any' has no compatible call signatures." 错误。我知道来自 getProperty()
的 属性 确实可以是任何类型,但是如何确定它是具有 (conf: {}): void
签名的函数?
在你的函数签名中有一个错误,key
参数应该是 K
类型,当你对参数使用常量时,这会给你更好的推断:
export function getProperty<T, K extends keyof T>(obj: T, key: string): T[K] {
if (key in obj) { return obj[key as K]; }
throw new Error(`Invalid object member "${key}"`);
}
let foo = {
fn (conf: {}): void {}
}
let fn = getProperty(foo, "fn");
fn({}); // callable
当您使用字符串形式且在编译时未验证的键时,问题是编译器无法真正帮助您解决任何问题。它将假定由于您索引了我的任意字符串,因此 return 类型可以是目标的任何有效字段类型。无法在运行时验证函数参数类型,因为它们将被删除,但您可以验证参数计数:
let property: Function = getProperty(this, name) as any;
if (typeof property === 'function' && property.length == 1)
{
property({});
}
它看起来不像 typeof
type guards exist for function types. It seems to be by design; see microsoft/TypeScript#2072(这个问题是关于 instanceof
类型保护的,但我猜这是类似的推理)。
但是,TypeScript 确实有 user-defined type guards,这意味着您可以编写一个函数,以任何您喜欢的方式缩小其参数的类型。
当代码编译为 JavaScript 时,TypeScript 的静态类型系统是 erased。在运行时,没有诸如 (conf: {}) => void
之类的东西可供您检查。如果您想编写运行时测试来区分类型 (conf: {}) => void
的值与其他类型的值,您将只能做到这一点。
你可以测试一下typeof x === "function"
。但这只是告诉你这是一个功能。它 不 表示函数有多少个参数以及它们的类型是什么。您还可以检查 if x.length === 1
以查看该函数是否需要一个参数,尽管在 Function.length
周围有涉及剩余参数和默认参数的注意事项。但现在你有点卡住了。
在运行时,任何关于函数参数 types 的信息都将被删除,如果这些函数最初来自 TypeScript 代码。您最多可以通过使用一些测试参数调用它并检查是否出现问题来“探测”该函数。但这是一个具有可能副作用的破坏性测试,并且违背了在调用函数之前检查函数类型是否正确的目的。
也许您不介意这个限制,并且假设 length
为 1
的函数是一个足够好的测试。或者也许你有一些其他的测试(例如,也许你可以添加一个名为 isOfRightType
的 属性 其值为 true
到你关心的所有这些函数,然后只测试那个 属性。这通过引入假阴性的可能性来消除假阳性)。一旦你知道你的运行时测试,你就可以做一个类型保护:
function isFunctionOfRightType(x: any): x is (conf: {})=>void {
return (typeof x === 'function') && (x.length === 1); // or whatever test
}
// ... later
let property: this[keyof this] = utils.getProperty(this, name);
if (isFunctionOfRightType(property)) { property(conf); } // no error now