gpt4 book ai didi

typescript - 应用函数名称和参数的函数类型

转载 作者:行者123 更新时间:2023-12-03 20:44:33 26 4
gpt4 key购买 nike

我正在尝试以正确的方式键入函数,该函数为该函数应用函数名称和参数。之后应用它并返回结果。这里的代码:

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' 的参数。”。
我怎样才能摆脱这个错误?
Link to playgound

最佳答案

编译器将无法理解这是类型安全的,因为它通常不能很好地推理依赖于尚未指定的泛型类型参数的类型的可分配性。存在一个 GitHub 问题,microsoft/TypeScript#24085 ,描述了这种情况。
事实上,有可能(但不太可能)在您的函数中,K可能被推断为 Keys本身而不是 "sum""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其余参数具有相关类型。即使可以,也不能很好地保持相关性,请参阅 microsoft/TypeScript#30581有关更多信息。
它也无法理解计算返回类型,因此您必须对其进行注释。您可以使用 ReturnType<F> utility type为了这。请注意,还有一个 Parameters<F> utility type你可以用它来代替写作 Args<F>你自己。

因此,归根结底,您只需要告诉编译器您所做的是类型安全的(您不会在某些联合类型的 apply() 上调用 funKey ,对吧?),因为它可以' t 验证它。要做到这一点,你需要像 type assertion 这样的东西。 .这里最容易使用的就是good old 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

好的,希望有帮助;祝你好运!
Playground link to code

关于typescript - 应用函数名称和参数的函数类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66231671/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com