外观
TypeScript 常用类型工具
作者:guo-zi-xin
更新于:9 个月前
字数统计:3k 字
阅读时长:13 分钟
Omit< T, K >
Omit< T, K >
用来从对象类型 T
中,删除指定属性 K
, 组成一个新的对象返回
typescript
interface A {
x: number;
y: number;
}
type T1 = Omit<A, 'x'>; // { y: number}
type T2 = Omit<A, 'y'>; // { x: number }
type T3 = Omit<A, 'x' | 'y'>; // { }
type T4 = Omit<A, 'z'>; // { x: number, y: number }
上面的示例中 Omit< T, K >
从对象类型 A
里删除指定属性, 返回剩下的属性
指定删除的键名Keys
可以是对象类型Type
中不存在的属性,但必须兼容string | number | symbol
Omit< T, K >
实现如下
typescript
type Omit<T, k extends keyof any> =
Pick<T, Exclude<keyof T, K>>
Pick< T, K >
Pick< T, K >
返回一个新的对象类型,第一个参数T
是一个对象类型,第二个参数K
是T
里面被选定的键名。
typescript
interface A {
x: number;
y: number;
}
type T1 = Pick<A, 'x'>; // { x: number }
type T2 = Pick<A, 'y'>; // { y: number }
type T3 = Pick<A, 'x' | 'y'> // { x: number, y: number }
上面示例中, Pick< T, K >
会从对象类型A
中挑选出指定的键名,组成一个新的对象类型。
指定的键名K
必须是对象键名T
中已经存在的键名,否则会报错:
typescript
interface A {
x: number;
y: number;
}
type T4 = Pick<A, 'z'> //报错
Pick< T, K >
实现如下
typescript
type Pick<T, K extends keyof T> = {
[P in K]: T[P]
}
Partial< T >
Partial< T >
返回一个新类型,将参数类型 T
的所有属性变为可选属性
typescript
interface A {
x: number;
y: number
}
type T1 = Partial<A>; // { x?: number; y?: number }
Partial< T >
实现如下
typescript
type Partial<T> = {
// 遍历T的属性名: 对应的属性值
[P in keyof T]?: T[P]
}
Required< T >
Required<T>
返回一个新类型,将参数类型T
的所有属性变为必选属性。 它与Partial
作用刚好相反。
typescript
interface A {
x?: number;
y:number
}
type T1 = Required<A> // { x: number; y: number }
Required< T >
的实现如下
typescript
type Required<T> = {
[P in keyof T]-?: T[P]
}
上述代码中, 符号-?
表示去除可选属性的"问号",使其变为必选属性。
相对应的,符号+?
表示增加可选属性的"问号",等同于?
因此, 前面的Partial< T >
的定义也可以写成下面这样:
typescript
type Partial<T> = {
[P in keyof T]+?: T[P]
}
Readonly< T >
Readonly< T >
返回一个新类型, 将参数类型T
的所有属性变为只读属性
typescript
interface A {
x: number;
y?: number
}
type T1 = Readonly<A> // { readonly x: number; readonly y?: number}
上面示例中, y
是可选属性,Readonly< T >
不会改变这一点, 只会让y
变为只读
Readonly
的实现如下
typescript
type Readonly<T> = {
readonly [P in keyof T]: T[P]
}
PS
我们可以自定义类型工具Mutable< T >
, 将参数类型的所有属性变为可变属性。
typescript
type Mutable<T> = {
-readonly [P in keyof T]: T[P]
}
上面代码中, -readonly
表示去除属性的只读标志。
相应地, +readonly
就表示增加只读标志,等同于readonly
。因此,Readonly< T >
的实现也可以写成下面这样:
typescript
type Readonly<T> = {
+readonly [P in keyof T]: T[P];
}
Readonly< T >
可以与Partial< T >
结合使用,将所有属性变成只读的可选属性
typescript
interface Person {
name: string;
age: number;
}
const worker:Readonly<Partial<Person>> = { name: '张三' }
worker.name = '李四' // 报错
Record< T, K >
Record<T, K>
返回一个对象类型,参数K
作为键名,参数T
作为键值类型。
typescript
type T = Record<'a', number> // { a: number }
上面示例中,Record< T, K >
的第一个参数 'a' 用作对象的键名,第二个参数'number' 是 'a'的键值类型。
参数K
可以是联合类型,这时会依次展开为多个键。
typescript
type T = Record<'a' | 'b', number> // { a: number, b: number}
上面示例中,第一个参数是联合类型'a' | 'b'
,展开成两个键名a
和b
。
如果参数T
是联合类型,表明键值是联合类型
typescript
type T = Record<'a', number | string>
参数K
的类型必须兼容string | number |symbol
类型,否则不能用作键名, 会报错。
Record< K,T >
的实现如下:
typescript
type Record<K extends string | number | symbol, T> = {
[P in K]: T
}
Exclude< T, U >
Exclude< T, U >
用来从联合类型T
里面,删除某些类型U
,组成一个新的类型返回。
typescript
type T1 = Exclude<'a' | 'b' | 'c', 'a'>; // 'b' | 'c'
type T2 = Exclude<'a' | 'b' | 'c', 'a' | 'b'>; // 'c'
type T3 = Exclude<string | (() => void), Function>; // string
type T4 = Exclude<string | string[], any[]>; // string
type T5 = Exclude<(() => void)| null, Function>; // null
type T6 = Exclude<200 | 400, 200 | 201>; // 400
type T7 = Exclude<number, boolean>; // number
Exclude< T, U >
的实现如下:
typescript
type Exclude<T, U> = T extends U ? never : T
上面代码中, 等号右边的部分,表示先判断T
是否兼容U
,如果是的话就返回never
类型,否则就返回当前类型T
。
由于never
类型是任何其它类型的子类型,它跟其它类型组成联合类型时候,可以直接将never
类型从联合类型中'消掉', 因此Exclude< T, U >
相当于删除兼容的类型, 剩下不兼容的类型
Extract< T, U >
Extract< T, U >
用来从联合类型T
中,提取指定类型U
,组成一个新类型返回。它与Exclude< T, U >
正好相反。
typescript
type T1 = Extract<'a' | 'b' | 'c', 'a'>; // 'a'
type T2 = Extract<'a' | 'b' | 'c', 'a' | 'b'>; // 'a' | 'b'
type T3 = Extract<'a' | 'b' | 'c', 'a' | 'd'>; // 'a'
type T4 = Extract<string | string[], any[]>; // string[]
type T5 = Extract<(() => void) | null, Function>; // () => void
type T6 = Extract<200 | 400, 200 | 201>; // 200
如果参数U
不包含在联合类型T
中, 则返回never类型
typescript
type T = Extract<string | number, boolean>; // never
Extract< T, U >
实现如下:
typescript
type Extract<T, U> = T extends U ? T : never
NonNullable< T >
NonNullable< T >
用来从联合类型T
中删除null
类型和 undefined
类型,组成一个新类型返回,也就是返回T
的非空类型版本
typescript
type T1 = NonNullable<string | number | undefined> // string | number
type T2 = NonNullable<string[] | null | undefined> // string[]
type T3 = NonNullable<boolean> // boolean
type T4 = NonNullable<number | null> // number
type T5 = NonNullable<string | undefined> // string
type T6 = NonNullable<null | undefined> // never
NonNullable< T >
的实现如下:
typescript
type NonNullable<T> = T & {}
上面代码中, T & {}
等同于求 T & Object
的交叉类型。由于 Typescript的非空值都是Object
的子类型,所以会返回自身;而null
和 undefined
不属于Object
, 会返回never
类型。
ReturnType< T >
ReturnType< T >
提取函数类型T
的返回值类型,作为一个新类型返回
typescript
type T1 = ReturnType<() => string> // string
type T2 = ReturnType<() => { a: string; b: number}> // { a: string, y: number}
type T3 = ReturnType<(s:string) => void> // void
type T4 = ReturnType<() => () => any[]> // () => any[]
type T5 = ReturnType<typeof Math.random> // number
type T6 = ReturnType<typeof Array.isArray> //boolean
如果参数类型是泛型参数,返回值取决于泛型类型。如果泛型不带有限制条件,就会返回unknown
typescript
type T7 = ReturnType<<T>() => T> // unknown
type T8 = ReturnType<<T extends U, U extends number[]>() => T> // number[]
如果类型不是函数,会报错
typescript
type T9 = ReturnType<boolean> //报错
type T0 = ReturnType<Function> //报错
any
和never
是两个特殊值,分别返回any
和 never
typescript
type T1 = ReturnType<any>; // any
type T2 = ReturnType<never>; // never
ReturnType< T >
的实现如下:
typescript
type ReturnType<T extends (...args: any) => any> = T extends (...args:any) => infer R ? R : any
Parameters< T >
Parameters< T >
从函数类型里面提取参数类型,组成一个元组返回
typescript
type T1 = Parameters<() => string> // []
type T2 = Parameters<(s: string) => void>; // [s: string]
type T3 = Parameters<<T>(arg:T) => T> //[arg:unknown]
type T4 = Parameters<(x : {a: number; b: string}) => void> // [x: { a: number, b:number }]
上面实例中,
Parameters< T >
的返回值会包括函数的参数名,这一点需要注意。
如果参数类型T
不是带有参数的函数形式, 会报错
typescript
type T5 = Parameters<string> // 报错
type T6 = Parameters<Function> //报错
any
和never
是两个特殊值,分别返回unknown[]
和 never
typescript
type T7 = Parameters<any>; // unknown[]
type T8 = Parameters<never>; // never
引申
Parameters< T >
主要用于从外部模块提供的函数类型中,获取参数类型。
typescript
interface IRequest {
first: string;
last: string
}
interface IReponse {
name: IRequest;
gift: string
}
export function getGift(name: IRequest, gift: string): IReponse {
// ...
}
上述示例中,模块只输出了函数getGift()
, 没有输出参数IRequest
和返回值IReponse
。
这时就可以通过Parameters< T >
和 ReturnType< T >
拿到这两个接口类型
typescript
type ParaT = Parameters<typeof getGift>[0] // IRequest
type ReturnT = ReturnType<typeof getGift> // IResponse
Parameters< T >
实现如下:
typescript
type Parameters<T extends (...args:any) => any> = T extends (...args: infer P) => any ? P : never
ConstructorParameters< T >
ConstructorParameters< T >
提取构造方法T
的参数类型,组成一个元祖类型返回
typescript
type T1 = ConstructorParameters<new (x: string, y: number) => object> // [x: string, y:number]
type T2 = ConstructorParameters<new (x?: string) => object> // [x?: string | undefined]
它可以返回一些内置构造方法的参数类型
typescript
type T3 = ConstructorParameters<ErrorConstructor> // [message?: string]
type T4 = COnstructorParameter<FunctionConstructor> // string[]
type T5 = ConstructorParameter<RegExpConstructor> //[pattern:string | RegExp, flags?: string]
如果参数类型不是构造方法,就会报错
typescript
type T6 = ConstructorParameters<string> //报错
type T7 = ConstructorParameters<Function> //报错
any
和never
是两个特殊值,分别返回unknown[]
和 never
typescript
type T7 = ConstructorParameters<any>; // unknown[]
type T8 = ConstructorParameters<never>; // never
ConstructorParameters< T >
实现如下:
typescript
type ConstructorParameters<T extends abstract new (...args: any) => any> =
T extends abstract new (...args: infer P) => any ? P : never
ThisParameterType< T >
ThisParameterType< T >
提取函数类型中的this
参数的类型
typescript
function toHex(this: number) {
return this.toString(16)
}
type T = ThisParameterType<typeof toHex> // number
如果函数没有 this
参数, 则返回unknown
ThisParameterType< T >
实现如下
typescript
type ThisParameterType<T> = T extends (this: infer U, ...args: never) => any ? U : unknown
InstanceType< T >
InstanceType< T >
提取构造函数的返回值的类型(即实例类型),参数T
是一个构造函数,等同于构造函数的ReturnType< T >
。
typescript
type T = InstanceType<new () => object> // object
上面示例中,类型参数是一个构造函数new () => object
, 返回值是该构造函数的实例类型(object
)。
示例:
typescript
type A = InstanceType<ErrorConstructor> // Error
type B = InstanceType<FunctionCOnstructor> // Function
type C = InstanceType<RegExpConstructor> // RegExp
上面示例中, InstanceType< T >
的参数都是Typescript内置的原生对象的构造函数类型,所以返回值就是这些构造函数的实例类型。
由于 Class作为类型, 代表实例类型, 要获取它的构造方法,必须把它当成值,然后用typeof
运算符获取它的构造方法类型
typescript
class D {
x = 0;
y = 0
}
type T = InstanceType<typeof D> // D
上面示例中,typeof C
是C
的构造方法类型,然后 InstanceType 就能获得实例类型,即C
本身。
如果类型参数不是构造方法,就会报错
typescript
type T1 = InstanceType<string>; // 报错
type T2 = InstanceType<Function>; // 报错
如果类型参数是any
或never
两个特殊值,分别返回any
和never
。
typescript
type T3 = InstanceType<any>; // any
type T4 = InstanceType<never>; // never
InstanceType< T >
的实现如下:
typescript
type InstanceType<T extends abstract new (...args: any) => any> =
T extends abstract new (...args: any) => infer R ? R : any
Awaited< T >
Awaited< T >
用来取出 Promise 的返回值类型,适合用在描述then()
方法和await
命令的参数类型。
typescript
type A = Awaited<Promise<string>> // string
它也可以返回多重 Promise 的返回值类型。
typescript
type B = Awaited<Promise<Promise<number>>>; // number
如果它的类型参数不是 Promise 类型,那么就会原样返回。
typescript
type C = Awaited<boolean | Promise<number>>; // number | boolean
上面示例中,类型参数是一个联合类型,其中的boolean
会原样返回,所以最终返回的是number|boolean
。
Awaited< T >
实现如下
typescript
type Awaited<T> =
T extends null | undefined ? T :
T extends object &
{
then(onfulfilled: infer F, ...args: infer _): any
} ? F extends (value: infer V, ...args: infer _) => any ?
Awaited<...> : never :
T
OmitThisParameter< T >
OmitThisParameter< T >
从函数类型中移除this
参数。
typescript
function toHex(this:number) {
return this.toString(16)
}
type T = OmitThisParameter<typeof toHex> // () => string
上面示例中,OmitThisParameter< T >
给出了函数toHex()
的类型,并将其中的this
参数删除。
如果函数没有 this 参数,则返回原始函数类型。
OmitThisParameter< T >
实现如下:
typescript
type OmitThisParameter<T> = unknown extends ThisParameterType<T> ?
T : T extends (...args: infer A) => infer R ? (...args: A) => R : T
ThisType< T >
ThisType< T >
不返回类型, 只用来跟其它类型组成交叉类型,用来提示Typescript其它类型的this
的类型
typescript
interface HelperThisValue {
logError: (error: string) => void
}
let helperFunctions:
{ [name: string]: Function } & ThisType<HelperThisValue> =
{
hello: function() {
this.logError('Error: Something Wrong') //正确
this.update() // 报错
}
}
上面示例中,变量helperFunctions
的类型是一个正常的对象类型与ThisType< HelperThisValue >
组成的交叉类型。
这里的ThisType
的作用是提示 TypeScript,变量helperFunctions
的this
应该满足HelperThisValue
的条件。所以,this.logError()
可以正确调用,而this.update()
会报错,因为HelperThisValue
里面没有这个方法。
注意📌
注意,使用这个类型工具时,必须打开noImplicitThis设置。
下面是另一个例子:
typescript
let obj: ThisType<{ x: number }> &
{ getX: () => number };
obj = {
getX() {
return this.x + this.y; // 报错
},
};
上面示例中,getX()
里面的this.y
会报错,因为根据ThisType< { x: number } >
,这个对象的this
不包含属性y
。
ThisType< T >
的实现就是一个空接口
typescript
interface ThisType<T> { }