我试图加深对Typescript中高级类型的了解,其中一种类型就是NonFunctionPropertyNames,例如,它仅提取给定对象的属性。
type NonFunctionPropertyNames<T> = { [K in keyof T]: T[K] extends Function ? never : K }[keyof T];
我可以理解大括号'{ [K in keyof T]: T[K] extends Function ? never : K }'
中的第一部分,我们在声明一个对象,并排除扩展Function的属性。使我感到困惑的是大括号[keyof T]
之后的部分。这看起来像数组{...}[keyof T]
的定义,但实际上它返回对象。
有人可以解释为什么仅大括号部分不足以声明类型吗?[keyof T]
的作用是什么。
答案 0 :(得分:1)
您看到的是一个类型查询。如果索引到对象类型,则将获得该属性的类型。例如:
type Foo = { foo: number }['foo'] // is number
如果您使用多个属性的并集进行索引,则会得到所有属性类型的并集:
type FooBar = { foo: number, bar: string, baz: boolean }['foo' | 'bar'] // string | number
如果使用所有键编制索引,则将获得所有属性类型的并集:
type FooBarBaz = { foo: number, bar: string, baz: boolean }['foo' | 'bar' | 'baz'] // string | number | boolean
但是要获得所有属性名称的并集,可以使用keyof
,因此上述类型也可以写为:
type O = { foo: number, bar: string, baz: boolean }
type FooBarBaz = O[keyof O] // string | number | boolean
类型{ [K in keyof T]: K }
的计算结果为对象类型,其中键的键入与表示键的文字类型相同:
type O = { foo: number, bar: string, baz: boolean }
type FooBarBaz = { [K in keyof O]: K } // { foo: "foo"; bar: "bar"; baz: "baz"; }
条件类型的作用是制作一些键,而不是与重新设置键的文字类型相同的类型,而是将它们键入为never
:
type O = { foo: number, bar: string, baz: () => boolean } // baz is a function now
type NonFunctionPropertyNames = { [K in keyof O]: O[K] extends Function ? never: K } // { foo: "foo"; bar: "bar"; baz: never; }
因此,新类型仍然具有原始键的所有键,但是某些键的类型为相应键的文字类型,有些键的类型为never
。我们想要的是一个具有我们刚刚构造的类型的键的所有值类型的并集,并且我们可以像以前一样使用keyof O
(因为类型具有与O
相同的键):>
type O = { foo: number, bar: string, baz: () => boolean } // baz is a function now
type NonFunctionPropertyNames = { [K in keyof O]: O[K] extends Function ? never: K }[keyof O] // "foo" | "bar" | never = "foo" | "bar" ;
never
始终从联合中删除,因此最后我们得到的是那些从不存在的对象键的联合。
设置O
为类型参数,您就有可重用的类型来获取非功能键:
type NonFunctionPropertyNames<O> = { [K in keyof O]: O[K] extends Function ? never : K }[keyof O]
type Foo = { foo: number, bar: string, baz: () => boolean } // baz is a function now
type NonFUnctionKeysOfFoo = NonFunctionPropertyNames<Foo> // "foo" | "bar"