这是我的代码
const functions={
top1: {
f1: () => 'string',
f2: (b: boolean, n: number) => 1
},
top2: {
f3: (b: boolean) => b
}
}
我想创建一个apply
函数,如下所示:
function apply (top: keyof typeof functions, functionName: string, inputs: any[]) {
return functions[top][functionName](...inputs)
}
以便我可以console.log以下值
console.log(apply('top1', 'f1', [])); // 'string'
console.log(apply('top1', 'f2', [true, 23])); // 1
console.log(apply('top2', 'f3', [false])); // false
apply('top2', 'f3', [1]); // show throw TS error
但是,在--strict
模式下,我遇到以下错误:
“元素隐式具有'any'类型,因为类型'...'没有索引签名”
这是可以理解的,因为functionName
是字符串,而不是keyof typeof functions[section]
。我该如何工作?
答案 0 :(得分:1)
您需要使用通用类型参数来捕获传递给函数的具体键。如果这样做,打字稿将允许您编制索引。
您还想使用一些条件类型来提取参数类型和返回类型,以使传入的参数和返回值类型具有类型安全性
const functions={
top1: {
f1: () => 'string',
f2: (b: boolean, n: number) => 1
},
top2: {
f3: (b: boolean) => b
}
}
type WeakParameters<T> = T extends (...a: infer A) => any ? A : never;
type WeakReturnType<T> = T extends (...a: any) => infer R ? R : never;
function apply<KOutter extends keyof (typeof functions),
KInner extends keyof (typeof functions[KOutter])>(
top: KOutter, functionName: KInner, inputs: WeakParameters<(typeof functions)[KOutter][KInner]>) : WeakReturnType<(typeof functions)[KOutter][KInner]>{
var fn = functions[top][functionName]; // OK
return (fn as unknown as (...a:any[])=> any)(...inputs)
}
console.log(apply('top1', 'f1', [])); // 'string'
console.log(apply('top1', 'f2', [true, 23])); // 1
console.log(apply('top2', 'f3', [false])); // false
apply('top2', 'f3', [1]); // show throw TS error
注意,不幸的是,我们仍然需要使用类型断言。尽管编译器允许我们使用functions
和top
索引到functionName
,但无法确定fn
是一个函数,因此我们不能直接调用它(因此类型断言as unknown as (...a:any[])=> any
)。同样由于这个原因(因为TS无法确定(typeof functions)[KOutter][KInner]
是一个函数),我们不能使用内置的条件类型Parameters
和ReturnType
来扩展参数类型和返回类型,我们需要编写自己的版本,这些版本不需要将type参数证明为函数(尽管调用该函数时,一切都会按预期进行)