For*_*eti 3 typechecking function-signature typescript
我有一个从对象获取属性的函数。
// 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}"`);
}
Run Code Online (Sandbox Code Playgroud)
我想检查返回的属性是否是具有给定签名的函数,然后使用提供的参数调用该属性。
getProperty()用于动态获取对象的方法之一并调用它。我试过:
let property: this[keyof this] = utils.getProperty(this, name);
if (typeof property === 'function') ) { property(conf); }
Run Code Online (Sandbox Code Playgroud)
但这给出了“无法调用类型缺少调用签名的表达式。类型'any'没有兼容的调用签名。” 错误。我知道来自的属性getProperty()确实可以是任何类型,但如何确定它是带有(conf: {}): void签名的函数?
它看起来并不像typeof型后卫的函数类型存在。这似乎是设计使然;请参阅microsoft/TypeScript#2072(该问题与instanceof类型保护有关,但我猜这是类似的推理)。
但是,TypeScript 确实有用户定义的类型保护,这意味着您可以编写一个函数,以您喜欢的任何方式缩小其参数的类型。
当代码编译为 JavaScript 时,TypeScript 的静态类型系统会被删除。在运行时,没有(conf: {}) => void您可以检查的东西。如果你想编写一个运行时测试来区分类型(conf: {}) => void的值和其他类型的值,你只能到此为止。
您可以测试是否typeof x === "function". 但这只是告诉你这是一个函数。它不表明函数采用多少个参数以及它们的类型。您还可以检查x.length === 1函数是否需要一个参数,尽管在Function.length涉及其余参数和默认参数方面存在一些警告。但现在你有点卡住了。
在运行时,任何关于函数参数类型的信息都将被删除,如果这些函数最初来自 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
Run Code Online (Sandbox Code Playgroud)