使用匹配的泛型参数调用泛型函数



我正在尝试编写一个函数,该函数将另一个函数及其args作为参数,然后使用所提供的args执行该函数并返回结果,同时保留类型。

只要提供的函数具有静态返回类型,就可以了。但是,当该函数的返回类型依赖于params时,我无法保留返回类型。

这是我失败的尝试。我希望它能澄清我试图实现的目标:

function f<A>(args: A) {
return args
}
// Calling the fuction directely works as expected:
const result = f('test') // OK: type of result is 'test'
// I tried this to be more explicit about the return type but it does not work
type ReturnTypeWithArgs<
F extends (args: any) => any,
A extends Parameters<F>[0],
> = F extends (args: A) => infer R ? R : never
// This is the function I'm trying to build
function callFunction<F extends (args: any) => any, A extends Parameters<F>[0]>(
f: F,
args: A,
): ReturnTypeWithArgs<F, A> {
return f(args)
}
// I'd like to get the same returned type when using callFunction. But it doesn't work:
const result2 = callFunction(f, 'test') // KO: typeof test2 is unknown

目前还没有纯粹的类型级方法来获取像<T>(t: A<T>) => R<T>这样的泛型函数类型和像X这样的参数类型,并让编译器告诉您如果使用类型为X的参数调用函数,返回类型是什么。不能像ReturnType<T>Parameters<T>实用程序类型那样使用条件类型推理;它最终只是用它们的(可能是隐式的(约束替换泛型类型参数,所以<T>(t: A<T>) => R<T>变成了(t: A<unknown>) => R<unknown>)

对于回答上述问题的类型运算符,在microsoft/TypeScript#40179上有一个公开的建议。它被标记为";等待更多反馈";,没有太多参与。如果你想看到它发生,你可以去那里,给它一个👍,并描述您的用例以及为什么需要它。。。但无论如何,它可能不会产生太大影响。目前,它还不是语言的一部分。


当前TypeScript对更高阶通用操作的支持都涉及到一些值级代码,这些代码使其成为已发出的JavaScript。如果调用一个泛型函数,它将执行您想要的类型操作,但如果没有函数,就无法执行。

幸运的是,可以通过重构为参数和返回类型使用单独的泛型类型参数来编写callFunction()函数。也就是说,不要从某个函数类型的F开始,并试图将其参数类型A和返回类型R区分开来。直接从AR开始。这将允许编译器从microsoft/TypeScript#30215:中实现的泛型函数中执行其高阶类型推断

function callFunction<A, R>(f: (arg: A) => R, args: A): R {
return f(args)
}
const result = callFunction(f, 'test') // string

这就是你想要看到的。您不会得到unknown,而是实际的string输入类型。


嗯,AR的小差异被推断为string而不是字面类型"test"。如果这很重要,你需要给编译器一个提示,在那里推断出更窄的类型。在microsoft/TypeScript#30680中有一个问题,要求找到一些简单的方法来实现这一点,但目前我使用的解决方法是将Narrowable提示类型定义为约束。它可能看起来像:

type Narrowable = string | number | boolean | null | undefined | bigint | {};
function callFunction<A extends Narrowable, R>(
f: (arg: A) => R,
args: A,
): R {
return f(args)
}
const result2 = callFunction(f, 'test') // "test"

游乐场链接到代码

最新更新