TypeScript 类型工具
TypeScript 类型工具
网道(WangDoc.com),互联网文档计划
TypeScript 提供了一些内置的类型工具,用来方便地处理各种类型,以及生成新的类型。
TypeScript 内置了17个类型工具,可以直接使用。
Awaited<Type>
#
Awaited<Type>
用来取出 Promise 的返回值类型,适合用在描述then()
方法和 await 命令的参数类型。
1 | // string |
上面示例中,Awaited<Type>
会返回 Promise 的返回值类型(string)。
它也可以返回多重 Promise 的返回值类型。
1 | // number |
如果它的类型参数不是 Promise 类型,那么就会原样返回。
1 | // number | boolean |
上面示例中,类型参数是一个联合类型,其中的boolean
会原样返回,所以最终返回的是number|boolean
。
Awaited<Type>
的实现如下。
1 | type Awaited<T> = |
ConstructorParameters<Type>
#
ConstructorParameters<Type>
提取构造方法Type
的参数类型,组成一个元组类型返回。
1 | type T1 = ConstructorParameters< |
它可以返回一些内置构造方法的参数类型。
1 | type T1 = ConstructorParameters< |
如果参数类型不是构造方法,就会报错。
1 | type T1 = ConstructorParameters<string>; // 报错 |
any
类型和never
类型是两个特殊值,分别返回unknown[]
和never
。
1 | type T1 = ConstructorParameters<any>; // unknown[] |
ConstructorParameters<Type>
的实现如下。
1 | type ConstructorParameters< |
Exclude<UnionType, ExcludedMembers>
#
Exclude<UnionType, ExcludedMembers>
用来从联合类型UnionType
里面,删除某些类型ExcludedMembers
,组成一个新的类型返回。
1 | type T1 = Exclude<'a'|'b'|'c', 'a'>; // 'b'|'c' |
Exclude<UnionType, ExcludedMembers>
的实现如下。
1 | type Exclude<T, U> = T extends U ? never : T; |
上面代码中,等号右边的部分,表示先判断T
是否兼容U
,如果是的就返回never
类型,否则返回当前类型T
。由于never
类型是任何其他类型的子类型,它跟其他类型组成联合类型时,可以直接将never
类型从联合类型中“消掉”,因此Exclude<T, U>
就相当于删除兼容的类型,剩下不兼容的类型。
Extract<Type, Union>
#
Extract<UnionType, Union>
用来从联合类型UnionType
之中,提取指定类型Union
,组成一个新类型返回。它与Exclude<T, U>
正好相反。
1 | type T1 = Extract<'a'|'b'|'c', 'a'>; // 'a' |
如果参数类型Union
不包含在联合类型UnionType
之中,则返回never
类型。
1 | type T = Extract<string|number, boolean>; // never |
Extract<UnionType, Union>
的实现如下。
1 | type Extract<T, U> = T extends U ? T : never; |
InstanceType<Type>
#
InstanceType<Type>
提取构造函数的返回值的类型(即实例类型),参数Type
是一个构造函数,等同于构造函数的ReturnType<Type>
。
1 | type T = InstanceType< |
上面示例中,类型参数是一个构造函数new () => object
,返回值是该构造函数的实例类型(object
)。
下面是一些例子。
1 | type A = InstanceType<ErrorConstructor>; // Error |
上面示例中,InstanceType<T>
的参数都是 TypeScript 内置的原生对象的构造函数类型,InstanceType<T>
的返回值就是这些构造函数的实例类型。
由于 Class 作为类型,代表实例类型。要获取它的构造方法,必须把它当成值,然后用typeof
运算符获取它的构造方法类型。
1 | class C { |
上面示例中,typeof C
是C
的构造方法类型,然后 InstanceType 就能获得实例类型,即C
本身。
如果类型参数不是构造方法,就会报错。
1 | type T1 = InstanceType<string>; // 报错 |
如果类型参数是any
或never
两个特殊值,分别返回any
和never
。
1 | type T1 = InstanceType<any>; // any |
InstanceType<Type>
的实现如下。
1 | type InstanceType< |
NonNullable<Type>
#
NonNullable<Type>
用来从联合类型Type
删除null
类型和undefined
类型,组成一个新类型返回,也就是返回Type
的非空类型版本。
1 | // string|number |
NonNullable<Type>
的实现如下。
1 | type NonNullable<T> = T & {} |
上面代码中,T & {}
等同于求T & Object
的交叉类型。由于 TypeScript 的非空值都属于Object
的子类型,所以会返回自身;而null
和undefined
不属于Object
,会返回never
类型。
Omit<Type, Keys>
#
Omit<Type, Keys>
用来从对象类型Type
中,删除指定的属性Keys
,组成一个新的对象类型返回。
1 | interface A { |
上面示例中,Omit<Type, Keys>
从对象类型A
里面删除指定属性,返回剩下的属性。
指定删除的键名Keys
可以是对象类型Type
中不存在的属性,但必须兼容string|number|symbol
。
1 | interface A { |
上面示例中,对象类型A
中不存在属性z
,所以就原样返回了。
Omit<Type, Keys>
的实现如下。
1 | type Omit<T, K extends keyof any> |
OmitThisParameter<Type>
#
OmitThisParameter<Type>
从函数类型中移除 this 参数。
1 | function toHex(this: Number) { |
上面示例中,OmitThisParameter<T>
给出了函数toHex()
的类型,并将其中的this
参数删除。
如果函数没有 this 参数,则返回原始函数类型。
OmitThisParameter<Type>
的实现如下。
1 | type OmitThisParameter<T> = |
Parameters<Type>
#
Parameters<Type>
从函数类型Type
里面提取参数类型,组成一个元组返回。
1 | type T1 = Parameters<() => string>; // [] |
上面示例中,Parameters<Type>
的返回值会包括函数的参数名,这一点需要注意。
如果参数类型Type
不是带有参数的函数形式,会报错。
1 | // 报错 |
由于any
和never
是两个特殊值,会返回unknown[]
和never
。
1 | type T1 = Parameters<any>; // unknown[] |
Parameters<Type>
主要用于从外部模块提供的函数类型中,获取参数类型。
1 | interface SecretName { |
上面示例中,模块只输出了函数getGift()
,没有输出参数SecretName
和返回值SecretSanta
。这时就可以通过Parameters<T>
和ReturnType<T>
拿到这两个接口类型。
1 | type ParaT = Parameters<typeof getGift>[0]; // SecretName |
Parameters<Type>
的实现如下。
1 | type Parameters<T extends (...args: any) => any> = |
Partial<Type>
#
Partial<Type>
返回一个新类型,将参数类型Type
的所有属性变为可选属性。
1 | interface A { |
Partial<Type>
的实现如下。
1 | type Partial<T> = { |
Pick<Type, Keys>
#
Pick<Type, Keys>
返回一个新的对象类型,第一个参数Type
是一个对象类型,第二个参数Keys
是Type
里面被选定的键名。
1 | interface A { |
上面示例中,Pick<Type, Keys>
会从对象类型A
里面挑出指定的键名,组成一个新的对象类型。
指定的键名Keys
必须是对象键名Type
里面已经存在的键名,否则会报错。
1 | interface A { |
上面示例中,对象类型A
不存在键名z
,所以报错了。
Pick<Type, Keys>
的实现如下。
1 | type Pick<T, K extends keyof T> = { |
Readonly<Type>
#
Readonly<Type>
返回一个新类型,将参数类型Type
的所有属性变为只读属性。
1 | interface A { |
上面示例中,y
是可选属性,Readonly<Type>
不会改变这一点,只会让y
变成只读。
Readonly<Type>
的实现如下。
1 | type Readonly<T> = { |
我们可以自定义类型工具Mutable<Type>
,将参数类型的所有属性变成可变属性。
1 | type Mutable<T> = { |
上面代码中,-readonly
表示去除属性的只读标志。
相应地,+readonly
就表示增加只读标志,等同于readonly
。因此,Readonly<Type>
的实现也可以写成下面这样。
1 | type Readonly<T> = { |
Readonly<Type>
可以与Partial<Type>
结合使用,将所有属性变成只读的可选属性。
1 | interface Person { |
Record<Keys, Type>
#
Record<Keys, Type>
返回一个对象类型,参数Keys
用作键名,参数Type
用作键值类型。
1 | // { a: number } |
上面示例中,Record<Keys, Type>
的第一个参数a
,用作对象的键名,第二个参数number
是a
的键值类型。
参数Keys
可以是联合类型,这时会依次展开为多个键。
1 | // { a: number, b: number } |
上面示例中,第一个参数是联合类型'a'|'b'
,展开成两个键名a
和b
。
如果参数Type
是联合类型,就表明键值是联合类型。
1 | // { a: number|string } |
参数Keys
的类型必须兼容string|number|symbol
,否则不能用作键名,会报错。
Record<Keys, Type>
的实现如下。
1 | type Record<K extends string|number|symbol, T> |
Required<Type>
#
Required<Type>
返回一个新类型,将参数类型Type
的所有属性变为必选属性。它与Partial<Type>
的作用正好相反。
1 | interface A { |
Required<Type>
的实现如下。
1 | type Required<T> = { |
上面代码中,符号-?
表示去除可选属性的“问号”,使其变成必选属性。
相对应地,符号+?
表示增加可选属性的“问号”,等同于?
。因此,前面的Partial<Type>
的定义也可以写成下面这样。
1 | type Partial<T> = { |
ReadonlyArray<Type>
#
ReadonlyArray<Type>
用来生成一个只读数组类型,类型参数Type
表示数组成员的类型。
1 | const values: ReadonlyArray<string> |
上面示例中,变量values
的类型是一个只读数组,所以修改成员会报错,并且那些会修改源数组的方法push()
、pop()
、splice()
等都不存在。
ReadonlyArray<Type>
的实现如下。
1 | interface ReadonlyArray<T> { |
ReturnType<Type>
#
ReturnType<Type>
提取函数类型Type
的返回值类型,作为一个新类型返回。
1 | type T1 = ReturnType<() => string>; // string |
如果参数类型是泛型函数,返回值取决于泛型类型。如果泛型不带有限制条件,就会返回unknown
。
1 | type T1 = ReturnType<<T>() => T>; // unknown |
如果类型不是函数,会报错。
1 | type T1 = ReturnType<boolean>; // 报错 |
any
和never
是两个特殊值,分别返回any
和never
。
1 | type T1 = ReturnType<any>; // any |
ReturnType<Type>
的实现如下。
1 | type ReturnType< |
ThisParameterType<Type>
#
ThisParameterType<Type>
提取函数类型中this
参数的类型。
1 | function toHex(this:number) { |
如果函数没有this
参数,则返回unknown
。
ThisParameterType<Type>
的实现如下。
1 | type ThisParameterType<T> = |
ThisType<Type>
#
ThisType<Type>
不返回类型,只用来跟其他类型组成交叉类型,用来提示 TypeScript 其他类型里面的this
的类型。
1 | interface HelperThisValue { |
上面示例中,变量helperFunctions
的类型是一个正常的对象类型与ThisType<HelperThisValue>
组成的交叉类型。
这里的ThisType
的作用是提示 TypeScript,变量helperFunctions
的this
应该满足HelperThisValue
的条件。所以,this.logError()
可以正确调用,而this.update()
会报错,因为HelperThisValue
里面没有这个方法。
注意,使用这个类型工具时,必须打开noImplicitThis
设置。
下面是另一个例子。
1 | let obj: ThisType<{ x: number }> & |
上面示例中,getX()
里面的this.y
会报错,因为根据ThisType<{ x: number }>
,这个对象的this
不包含属性y
。
ThisType<Type>
的实现就是一个空接口。
1 | interface ThisType<T> { } |
字符串类型工具 #
TypeScript 内置了四个字符串类型工具,专门用来操作字符串类型。这四个工具类型都定义在 TypeScript 自带的.d.ts
文件里面。
它们的实现都是在底层调用 JavaScript 引擎提供 JavaScript 字符操作方法。
Uppercase<StringType>
#
Uppercase<StringType>
将字符串类型的每个字符转为大写。
1 | type A = 'hello'; |
上面示例中,Uppercase<T>
将 hello 转为 HELLO。
Lowercase<StringType>
#
Lowercase<StringType>
将字符串的每个字符转为小写。
1 | type A = 'HELLO'; |
上面示例中,Lowercase<T>
将 HELLO 转为 hello。
Capitalize<StringType>
#
Capitalize<StringType>
将字符串的第一个字符转为大写。
1 | type A = 'hello'; |
上面示例中,Capitalize<T>
将 hello 转为 Hello。
Uncapitalize<StringType>
#
Uncapitalize<StringType>
将字符串的第一个字符转为小写。
1 | type A = 'HELLO'; |
上面示例中,Uncapitalize<T>
将 HELLO 转为 hELLO。
参考链接 #
本文转自 https://wangdoc.com/typescript/utility,如有侵权,请联系删除。