我有一个从对象获取属性的函数。
// 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
签名的函数?
答案 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({});
}