TypeScript - 检查对象的属性是否是具有给定签名的函数

时间:2018-05-16 12:45:52

标签: typescript typechecking function-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); }

但这给出了“无法调用类型缺少调用签名的表达式。输入'any'没有兼容的调用签名。”错误。我理解来自getProperty()的属性确实可以是任何类型但是如何确定它是具有(conf: {}): void签名的函数?

2 个答案:

答案 0 :(得分:3)

对于函数类型,它看起来不像typeof type guards。这似乎是by design(该问题与约public static void Main() { string[] separator = { ", ", "; " }; string names = "Peter, John; Andy, David"; string[] substrings = names.Split(separator, StringSplitOptions.None); foreach(var name in substrings) { Console.WriteLine(name); } } 类型的警卫有关,但我猜测它的推理类似。)

但是,TypeScript确实有user-defined type guards,这意味着您可以编写一个函数,以任何方式缩小其参数的类型。那么,什么运行时测试会确定某个值instanceof是否是x类型的函数?当然,您可以测试(conf: {}) => void。这并不表示该函数将采用任何特定类型的参数而不返回任何内容。也许您只知道从typeof x === "function"中提取的任何函数都是正确的类型。如果没有,您应该弄清楚如何区分运行时的差异。 (是getProperty?还有其他一些显着特征吗?)

一旦了解了运行时测试,就可以建立一个类型保护:

x.length === 1

希望有所帮助。祝你好运!

答案 1 :(得分:1)

在你的函数签名中有一个错误,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 

当您使用字符串且未在编译时验证的密钥时,编译器无法真正帮助您解决任何问题。它会假设,因为您索引我的任意字符串,返回类型可以是目标的任何有效字段类型。在运行时无法验证函数参数类型,因为它们将被擦除,您可以通过以下方式验证参数计数:

let property:  Function = getProperty(this, name) as any;
if (typeof property === 'function' && property.length == 1)  
{ 
    property({}); 
}