如何获取“ keyof T”的子集,其值T [K]是Typescript中的可调用函数

时间:2018-07-19 09:35:57

标签: typescript

我想根据keyof T的类型过滤T[keyof T]

它应该像这样工作:

type KeyOfType<T, U> = ...

KeyOfType<{a: 1, b: '', c: 0, d: () => 1}, number> === 'a' | 'c'

KeyOfType<{a: 1, b: '', c: 0: d: () => 1}, string> === 'b'

KeyOfType<{a: 1, b: '', c: 0: d: () => 1}, Function> === 'd'

这可能吗?

2 个答案:

答案 0 :(得分:4)

您可以使用条件类型和映射类型

type KeyOfType<T, U> = {[P in keyof T]: T[P] extends U ? P: never}[keyof T]

让我们分解一下。

我们可以从一个映射类型开始,该类型具有与原始T相同类型的属性,这是一个简单的标准映射类型:

type KeyOfType<T> = { [P in keyof T]: T[P] } // New Type same as the original

T[P]是类型查询,表示类型P中键T的类型。我们可以将其更改为P,这意味着新属性的类型与其名称相同:

type KeyOfType<T> = { [P in keyof T]: P }
// So
KeyOfType<{ a: number, b: string }> == { a: 'a', b: 'b' }

我们可以向该类型添加类型查询,以再次获取该类型的所有键。通常,构造T[keyof T]获取类型的所有属性类型。将其应用于属性类型与键名相同的映射类型,我们基本上回到keyof T

type KeyOfType<T> = { [P in keyof T]: P }[keyof T]
// So
KeyOfType<{ a: number, b: string }> ==  'a'|'b' 

现在我们可以向o添加条件类型,而不必总是选择P。由于A | never == A,如果原始属性(T[P])的类型不符合特定约束,我们可以将映射类型中的属性的类型设置为Never。

为表达约束,我们添加了一个额外的泛型参数U,并使用了条件类型,其形式为T extends U ? TypeIfTrue: TYpeIfFalse。放在一起,我们得到:

type KeyOfType<T, U> = {[P in keyof T]: T[P] extends U ? P: never}[keyof T]

答案 1 :(得分:1)

很棒的解释!!

我还要补充一点,您可以将 U 的默认类型设置为 T 的任意键,如下所示:

type Keys<T> = {[P in keyof T]: T[P]}[typeof P]

type KeyOfType<T, U = Keys<T>> = {[P in keyof T]: T[P] extends U ? P : never}[keyof T]

我将 U = Keys<T> 添加到 KeyOfType 的通用定义

谢谢解释!