我想根据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'
这可能吗?
答案 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
的通用定义
谢谢解释!