Typescript 条件类型结合映射类型文档示例说明

Typescript Conditional Types combined with mapped types documentation example clarification

我正在尝试了解 TypeScript 2.8 中引入的条件类型并阅读相关文档。

下面的例子可以在下面看到link https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-8.html

本节有一个例子:

type FunctionPropertyNames<T> = { [K in keyof T]: T[K] extends Function ? K : never }[keyof T];

我理解了这一部分 { [K in keyof T]: T[K] extends Function ? K : never } 它在其中选择所有类型为 Function 的键。但是我不明白为什么最后会有一个数组类型的语法 [keyof T] 它在那里做什么?为什么需要它?

提前致谢。

这叫做 lookup type

使用数组访问语法,我们可以获得传入的所有 属性 类型的联合。

({ a: string, b: number, c: object })['a' | 'b'] // -> string | number

让我们看一个例子,其中 T 是:

{
  a: () => void,
  b: () => void,
  c: string
}

FunctionPropertyNames<T> 的预期结果将是 'a' | 'b'

映射类型生成如下对象类型:

{
  a: 'a',
  b: 'b',
  c: never
}

但这不是我们想要的,我们需要 属性 名称作为联合类型。这是查找类型的用武之地。

在示例中,我们使用了 T 的所有键,所以基本上:

({ a: 'a', b: 'b', c: never })['a' | 'b' | 'c'] // -> 'a' | 'b' | never

returns 'a' | 'b' | nevernever 无关紧要,所以 TypeScript 删除了它,我们得到 'a' | 'b'

一开始假设代码段只有以下内容

type FunctionPropertyNames<T> = { [K in keyof T]: T[K] extends Function ? K : never };

没有数组访问器。所以基本上非函数被映射到 never 而函数被映射到相应类型的键,即它们的函数名称。

这意味着

type Foo = FunctionPropertyNames<{
    bar: string;
    baz: number;
    boo(): void;
    ping(a: number): string;
}>;

type Foo = {
    bar: never;
    baz: never;
    boo: "boo";
    ping: "ping";
};

都一样。当我们最终使用数组访问器并使用 [keyof T] 访问具有 T 中键的所有类型的属性时(此时几乎所有),我们得到了所有类型的联合,而没有 never 因为 never 总是被丢弃。