网站搜索

在 TypeScript 中按类型排除函数参数


我希望能够接受一个具有 n 个参数的函数,并返回一个基于该函数的类型,其中任何类型为 x 的参数都不再出现在函数类型中。例如:

function myTestFunction(email: string, context: TestContext, password: string): void {
  ...
}

我想在那个上使用一种类型来创建像这样的函数定义:

function myTestFunction(email: string, password: string): void {
  ...
}

我设法用这个做到了:

type Filter<T> = T extends [] 
  ? [] 
  : T extends [infer A, ...infer B] 
    ? A extends TestContext 
      ? Filter<B>
      : [A, ...Filter<B>]
    : T;
type ConvertFunction<T> = T extends (...args: any[]) => any
  ? (...args: Filter<Parameters<T>>) => ReturnType<T>
  : T;

唯一的问题是参数名称丢失,签名变为:

function myTestFunction(args_0: string, args_1: string): void {
  ...
}

请问如何在不丢失参数名称的情况下做到这一点?

答案#1

嗯,我觉得你做不到这件事。

你可以做的是展开一个元组以保留名称

type MyTup = [a: string, b: number]
type MyTup2 = [...MyTup] // [a: string, b: number]

然而,当你从元组中获取单个值时,它将失去其名称。

type MyTup = [a: string, b: number]
type MyTup2 = [MyTup[0], MyTup[1] // [string, string]

如果你将一个未命名的成员与一个命名元组合并,所有成员都会变为未命名:

type MyTup = [a: string, b: number]
type B = [MyTup[0], ...MyTup] // [string, string, string]

当然,你可以把名字加回来,但据我所知,没有办法真正获取元组成员的名字。所以没有办法通用地做到这一点。

type B = [asdf: MyTup[0], qwerty: MyTup[1]] // [asdf: string, qwerty: string]

这意味着当你这样做时:

[A, Filter<B>]

那么你正在生成一个未命名的元组。而这种反复重新构建元组的递归方法,目前是以通用方式添加或移除元组成员的唯一方式。


所以我可能是错的,但我不确定在当前版本的 TypeScript 中这是否可行。