TypeScript 官方提供了许多内置类型,无需导入即可使用,基于这些类型工具,我们可以快速的处理各种类型以及生成新的类型,以下列举了几个实用类型的使用方式及对应源码:
Partial<T>
将类型参数 T
中的所有属性变为可选属性
typescript
// 源码
type Partial<T> = {
[P in keyof T]?: T[P]
}
interface User {
name: string
age: number
}
type T = Partial<User>
// 等价于
type T = {
name?: string
age?: number
}
Required<T>
将类型参数 T
中的所有属性变为必选属性,,移除了 T 每个属性上的可选属性修饰符 ?
typescript
// 源码
type Required<T> = {
[P in keyof T]-?: T[P]
}
interface User {
name?: string
age?: number
}
type T = Required<User>
// 等价于
type T = {
name: string
age: number
}
Readonly<T>
将类型参数 T
中的所有属性变为只读属性
typescript
// 源码
type Readonly<T> = {
readonly [P in keyof T]: T[P]
}
interface User {
name: string
age: number
}
type T = Readonly<User>
// 等价于
type T = {
readonly name: string
readonly age: number
}
Record<K,T>
类型参数 K
为对象属性名的联合类型,类型参数 T
为对象属性值的类型,因为类型参数 K
是用作对象属性名类型,所以实际类型参数 K
必须能够赋值给 string | number | symbol
类型,只有这些类型能够作为对象属性名类型。
个人理解:批量的为对象的属性声明类型,K
为属性名的联合类型。其中对象的所有的属性名均来自 K
,T
为属性值类型,将对象中的所有属性都声明为 T
类型
typescript
// 源码
type Record<K extends keyof any, T> = {
[P in K]: T
}
interface Position {
x: string
y: string
}
type T = Record<keyof Position, number>
// 等价于
type T = {
x: number
y: number
}
Exclude<T,U>
从联合类型 T
中删除可以赋值给联合类型 U
的类型
typescript
// 源码
// 先判断类型 T 是否兼容类型 U,是则返回 never 类型,否则返回 T 类型,由于 never 是任何其他类型的子类型,它跟其他类型组成联合类型时,可以直接将never类型从联合类型中"消掉",因此 Exclude<T, U> 就相当于删除兼容的类型,剩下不兼容的类型
type Exclude<T, U> = T extends U ? never : T
interface User {
name: string
age: number
}
type T = Exclude<keyof User, 'name'>
// 等价于
type T = 'age'
type T2 = Exclude<keyof User, 'name' | 'email'>
// 等价于
type T2 = 'age'
Extract<T,U>
Extract<T, U>
工具类型与 Exclude<T, U>
工具类型是互补的,该类型能够从联合类型 T
中挑选可以赋值给联合类型 U
的类型
typescript
// 源码
type Extract<T, U> = T extends U ? T : never
interface User {
name: string
age: number
}
type T = Extract<keyof User, 'name'>
// 等价于
type T = 'name'
type T2 = Extract<keyof User, 'name' | 'email'>
// 等价于
type T2 = 'name'
Pick<T,K>
从已有对象类型中挑选一个或多个指定的属性并保留它们的类型和修饰符,然后构造出一个新的对象类型。类型参数 T
为对象类型,类型参数 K
为从类型参数 T
中挑选的属性名类型
typescript
// 源码
type Pick<T, K extends keyof T> = {
[P in K]: T[P]
}
interface User {
name: string
age?: number
}
type T = Pick<User, 'age'>
// 等价于
type T = {
age?: number
}
type T2 = Pick<User, 'name' | 'age'>
// 等价于
type T2 = {
name: string
age?: number
}
Omit<T,K>
Omit<T, K>
工具类型与 Pick<T, K>
工具类型是互补的,它能够从已有对象类型中剔除给定的属性,然后构建出一个新的对象类型。类型参数 T
为对象类型,类型参数 K
为从类型参数 T
中挑选的需要剔除的属性名类型,也可以是对象类型 T
中不存在的类型
typescript
// 源码
type Omit<T, K extends keyof any> = {
[P in Exclude<keyof T, K>]: T[P]
}
interface User {
name: string
age: number
}
type T = Omit<User, 'age'>
// 等价于
type T = {
name: string;
}
type T2 = Omit<User, 'email'>
// 等价于
type T2 = {
name: string;
age: number;
}
NonNullable<T>
从联合类型参数 T
中剔除 null
类型和 undefined
类型,也就是将类型 T
变为一个非空类型
typescript
// 源码
// T & {}等同于求 T & Object 的交叉类型。由于 TypeScript 的非空值都属于 Object 的子类型,所以会返回自身;而 null 和 undefined 不属于Object,会返回 never 类型
type NonNullable<T> = T & {}
// 也可以这样写
type NonNullable<T> = T extends null | undefined ? never : T
type K = number | string | null | undefined
type T = NonNullable<K>
// 等同于
type T = string | number
Parameters<T>
从函数类型 T
中提取参数类型并组成元祖类型返回
typescript
// 源码
// infer 关键字用来定义泛型里面推断出来的类型参数,通常需要和 extends 关键字搭配使用
type Parameters<T extends (...args: any) => any> = T extends (
...args: infer P
) => any
? P
: never
type T = Parameters<(a: number, b: string) => string>
// 等价于
type T = [a: number, b: string]
type T2 = Parameters<() => any>
// 等价于
type T2 = []
type T3 = Parameters<<T>(arg: T) => T>
// 等价于
type T3 = [arg: unknown]
如果函数类型 T
不是带有参数的函数形式,会报错
typescript
// 以下类型会报错
type T1 = Parameters<string>
type T2 = Parameters<Function>
any
和 never
的特殊情况
typescript
type T1 = Parameters<any>
// 等价于
type T1 = unknown[]
type T2 = Parameters<never>
// 等价于
type T2 = never
ConstructorParameters<T>
提取构造方法 T
的参数类型,并组成元组类型返回
typescript
// 源码
type ConstructorParameters<T extends abstract new (...args: any) => any> =
T extends abstract new (...args: infer P) => any ? P : never
type T = ConstructorParameters<new (a: number, b: number) => object>
// 等价于
type T = [a: number, b: number]
如果参数类型不是构造方法,就会报错
typescript
// 以下代码会报错
type T1 = ConstructorParameters<string>
type T2 = ConstructorParameters<Function>
any
和 never
的特殊情况
typescript
type T1 = ConstructorParameters<any>
// 等价于
type T1 = unknown[]
type T2 = ConstructorParameters<never>
// 等价于
type T2 = never
它可以返回一些内置构造方法的参数类型
typescript
type T1 = ConstructorParameters<ErrorConstructor>
// type T1 = [message?: string | undefined]
type T2 = ConstructorParameters<FunctionConstructor>
// type T2 = string[]
type T3 = ConstructorParameters<RegExpConstructor>
// type T3 = [pattern: string | RegExp, flags?: string | undefined]
ReturnType<T>
获取函数类型 T
的返回值类型
typescript
// 源码
type ReturnType<T extends (...args: any) => any> = T extends (
...args: any
) => infer R
? R
: any
type T = ReturnType<() => { a: number; b: number }>
// 等价于
type T = {
a: number
b: number
}
如果参数类型是 T
,返回值取决于泛型类型,如果泛型不带限制条件,就会返回 unknown
typescript
type T1 = ReturnType<<T>() => T>
// 等价于
type T1 = unknown
type T2 = ReturnType<<T extends U, U extends number[]>() => T>
// 等价于
type T2 = number[]
如果类型不是函数,会报错
typescript
// 以下代码会报错/* */
type T1 = ReturnType<number>
type T2 = ReturnType<Function>
any
和 never
的特殊情况,分别返回 any
和 never
typescript
type T1 = ReturnType<any>
// 等价于
type T1 = any
type T2 = ReturnType<never>
// 等价于
type T2 = never
InstanceType<T>
获取构造函数的返回值类型,即实例类型
typescript
// 源码
type InstanceType<T extends abstract new (...args: any) => any> =
T extends abstract new (...args: any) => infer R ? R : any
class User {
name: 'kunkun'
age: 18
}
type T = InstanceType<typeof User>
// 等价于
type T = User
如果类型参数不是构造方法,就会报错
typescript
// 以下代码会报错
type T1 = InstanceType<string>
type T2 = InstanceType<Function>
any
和 never
的特殊情况,分别返回 any
和 never
typescript
type T1 = InstanceType<any>
// 等价于
type T1 = any
type T2 = InstanceType<never>
// 等价于
type T2 = never
它可以返回一些内置构造函数类型
typescript
type T1 = InstanceType<ErrorConstructor>
// 等价于
type T1 = Error
type T2 = InstanceType<FunctionConstructor>
// 等价于
type T2 = Function
type T3 = InstanceType<RegExpConstructor>
// 等价于
type T3 = RegExp
ThisParameterType<T>
获取函数类型 T
中 this
参数的类型
typescript
type ThisParameterType<T> = T extends (this: infer U, ...args: never) => any
? U
: unknown
function fn(this: number) {
return this.toString()
}
type T = ThisParameterType<typeof fn>
// 等价于
type T = number
如果函数中没有 this
参数,则返回 unknown
typescript
function fn(a: number) {}
type T = ThisParameterType<typeof fn>
// 等价于
type T = unknown
OmitThisParameter<T>
从函数类型 T
中剔除 this
参数类型
typescript
// 源码
type OmitThisParameter<T> = unknown extends ThisParameterType<T>
? T
: T extends (...args: infer A) => infer R
? (...args: A) => R
: T
function fn(this: number, a: number) {
return this.toString()
}
type T = OmitThisParameter<typeof fn>
// 等价于
type T = (a: number) => string
ThisType<T>
在 TypeScript
中,默认对象中方法中的 this
是 any
类型,可以使用 ThisType<T>
声明 this
类型,在使用该类型工具时,需要打开 noImplicitThis
设置
tsconfig.json
json
{
"compilerOptions": {
"noImplicitThis": true
}
}
typescript
// 源码
interface ThisType<T> {}
interface User {
name: string
age: number
hobby: string[]
sayHi: () => void
}
type T = ThisType<User>
// ThisType<User> 使得 sayHi 方法内部的 this 被明确为 User 类型
const user: User & ThisType<User> = {
name: 'kunkun',
age: 18,
hobby: ['唱', '跳', 'rap'],
sayHi: function () {
console.log(
`你好,我是${this.name},今年${this.age}
岁,我的爱好是:${this.hobby.join(',')}`
)
},
}
Awaited<T>
用于获取 Promise
的返回值类型,适合在描述 then
方法和 await
命令的参数类型
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
type T = Awaited<Promise<string>>
// 等价于
type T = string
它也可以返回多重 Promise
的返回值类型
typescript
type T = Awaited<Promise<Promise<number>>>
// 等价于
type T = number
如果它的类型参数不是 Promise
类型,那么就会原样返回
typescript
type T2 = Awaited<boolean | Promise<number>>
// 等价于
type T2 = number | boolean
字符串类型工具
typescript
type T = 'hello'
// Uppercase<T>:将字符串类型的每个字符转为大写
type T2 = Uppercase<T>
// type T2 = "HELLO"
// Lowercase<T>:将字符串的每个字符转为小写
type T3 = Lowercase<T2>
// type T3 = "hello"
// Capitalize<T>:将字符串的第一个字符转为大写
type T4 = Capitalize<T>
// type T4 = "Hello"
// Uncapitalize<T>:将字符串的第一个字符转为小写
type T5 = Uncapitalize<T2>
// type T5 = "hELLO"