我试图以适当的方式键入为该功能应用功能名称和参数的功能。之后应用它并返回结果。这里的代码:
const sum = (a: number, b: number) => a + b
const concat = (a: string, b: string, c: string) => a + b + c
const funs = {
sum,
concat
}
type Keys = 'sum' | 'concat'
type Args<T> = T extends (...args: infer R) => any ? R : never
type Sum = Args<typeof sum>
type Concat = Args<typeof concat>
function apply<K extends Keys>(funKey: K, ...args: Args<typeof funs[K]>) {
// here I get the error 'An argument for 'a' was not provided.'
return funs[funKey](...args)
}
const test1 = apply('sum', 1, 2)
const test2 = apply('concat', 'str1', 'str2', 'str3' )
在apply
函数内部,出现错误“未提供'a'的参数”。我如何摆脱这个错误?
编译器将无法理解这是类型安全的,因为对于通常依赖于尚未指定的通用类型参数的类型,它通常不能很好地说明其可分配性。存在一个存在GitHub问题microsoft / TypeScript#13995,它描述了这种情况。
实际上,可能(但不太可能)在您的函数K
中将Keys
其推断为本身而不是"sum"
or "concat"
。如果您这样做:
const oops = apply(Math.random() < 0.5 ? "sum" : "concat", "a", "b", "c"); // oopsie
console.log(oops); // 50% chance of "abc", 50% chance of "ab"
然后您会看到编译器在技术上正确无误,因为您所做的操作类型不安全。您想告诉编译器K
将是的成员之一 Keys
,而您不能这样做。有关允许的功能建议,请参阅microsoft / TypeScript#27808。
无论如何,编译器无法将funKey
参数和args
rest参数视为具有相关类型。即使可以,但保持相关性也不是很好,请参阅microsoft / TypeScript#30581了解更多信息。
它也无法理解计算返回类型,因此您必须对其进行注释。您可以为此使用ReturnType<F>
实用程序类型。请注意,还有一种Parameters<F>
实用程序类型,您可以使用它来代替Args<F>
自己编写。
因此,归根结底,您只需要告诉编译器您正在执行的操作是类型安全的(您不会调用apply()
某些union-typed funKey
,对吗?),因为它无法对其进行验证。为此,您需要类似类型断言的东西。在这里最容易使用的是好旧的any
:
type Funs = typeof funs;
function apply<K extends Keys>(funKey: K, ...args: Parameters<Funs[K]>): ReturnType<Funs[K]> {
return (funs[funKey] as any)(...args);
}
这将使您能够做疯狂的事情,例如return (funs[funKey] as any)(true)
,因此您应该小心。类型安全性略高一些,但复杂得多的一点是将其表示funs[funKey]
为一个函数,该函数以某种方式接受每个函数期望的参数,并返回两种返回类型。像这样:
type WidenFunc<T> = ((x: T) => void) extends ((x: (...args: infer A) => infer R) => any) ?
(...args: A) => R : never;
function apply<K extends Keys>(funKey: K, ...args: Parameters<Funs[K]>): ReturnType<Funs[K]> {
return (funs[funKey] as WidenFunc<Funs[Keys]>)(...args);
}
这WidenFunc<Funs[Keys]>
是(...args: [number, number] | [string, string, string]) => number & string
。这是一种胡说八道的函数类型,但是如果您将类似的参数传递给(true)
而不是,它将至少会抱怨(...args)
。
无论如何,这两个都应该起作用:
const test1 = apply('sum', 1, 2) // number
const test2 = apply('concat', 'str1', 'str2', 'str3') // string
好吧,希望能有所帮助;祝好运!
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句