本文主要记录下 TypeScript 中常用的泛型工具,日常学习总结篇。
extends
这里主要介绍下 extends 关键字在 TS 中的两种用法,即接口继承和条件判断。
1⃣️、接口继承
extends 做继承功能,同 ES6 的 Class 语法用它来做类的继承用法类似。实例代码如下:
interface IName {
name: string
}
interface IAge {
age: number
}
interface IPerson extends IAge, IName {
sex: string
}
const obj: IPerson = {
age: 18,
name: 'Jenny',
sex: '女'
}
上述代码中,IAge 和 IName 两个接口,分别定义了 age,name属性,IPerson 则使用 extends 多重继承的方法,继承了 IAge 和 IName,同时定义了自身属性 sex,此时 IPerson 除了自身属性外,还同时拥有了来自 IAge 和 IName 的属性。
2⃣️、条件判断
条件判断会以一个条件表达式进行类型关系检测,从而在两种类型中选择其一。
T extends U ? X : Y
上述代码含义为:如果 T 包含的类型是 U 包含的类型的 '子集',那么取结果 X,否则取结果 Y。
实现一个简单的示例代码:
type WhatType = T extends null | undefined ? never : T
let typeString: WhatType = 'abc' // string 类型
let typeNull: WhatType // never 类型
上述代码含义为:如果泛型参数 T 为 null 或 undefined,那么取 never,否则直接返回 T。
在条件类型语句中,可以用 infer 声明一个类型变量,并且对它进行使用。
infer 可以在 extends 的条件语句中推断待推断的类型。示例代码如下:
type ParamType = T extends (...args: infer P) => any ? P : T;
interface User {
name: string;
age: number;
}
type Func = (user: User) => void;
type Param = ParamType; // Param = User
type AA = ParamType; // string
keyof 操作符用来获取某种类型的所有 key 值,返回一个联合类型。示例代码如下:
interface IPerson {
name: string,
age: number
}
type allKey1 = keyof IPerson // 'name' | 'age'
type allKey2 = keyof IPerson[] // 'length | 'toString | 'pop' | 'push' | 'concat' | 'join' | ......
type allKey3 = keyof { [x: string]: IPerson } // string | number
typeof 操作符用来在类型上下文中获取变量或者属性的类型。示例代码如下:
interface IPerson {
name: string,
age: number
}
const user: IPerson = {
name: 'jenny',
age: 18
}
type student = typeof user // IPerson
in 操作符用来遍历枚举类型。示例代码如下:
type keys = 'a' | 'b' | 'c'
type obj = {
[p in keys]: any
} // { a: any, b: any, c: any}
Partial
type Partial = {
[P in keyof T]?: T[P]
}
以上代码中,首先通过 keyof T 拿到 T 的所有属性名,然后使用 in 进行遍历,将值赋给 P,最后通过 T[P] 取得相应的属性值。中间的 ? 号,用于将所有属性变为可选。示例代码如下:
interface IPerson {
name: string,
age: number
}
type person = Partial
// 相当于
// type person = {
// name?: string | undefined;
// age?: number | undefined;
// }
Required
type Required = {
[P in keyof T]-?: T[P];
};
-? 的作用就是把可选属性的可选性去掉,使该属性变成必选项。示例代码如下:
interface IPerson {
name?: string,
age?: number
}
type person = Required
// 相当于
// type person = {
// name: string;
// age: number;
// }
Readonly
type Readonly = {
readonly [P in keyof T]: T[P]
}
在每一个 key 前面加上 readonly。示例代码如下:
interface IPerson {
name: string,
age: number
}
type person = Readonly
// 相当于
// type person = {
// readonly name: string;
// readonly age: number;
// }
const obj:person = {
name: 'lucy',
age: 18
}
// 此处 TS 会报错:无法为 name 重新赋值,因为它是只读属性
obj.name="jenny"
Mutable
type Mutable = {
-readonly [P in keyof T]: T[P]
}
在每一个 key 前面加上 -readonly。示例代码如下:
interface IPerson {
readonly name: string,
readonly age: number
}
type person = Mutable
// 相当于
// type person = {
// name: string;
// age: number;
// }
Exclude
type Exclude = T extends U ? never : T;
实现效果为从 T 中去除 T 与 U 的交集后的类型。示例代码如下:
type exclude0 = Exclude // string | boolean
type exclude1 = Exclude<'a' | 'b' | 'c', 'a' | 'c'> // 'b'
Extract
type Extract = T extends U ? T : never;
这个和上面的 Exclude 恰好相反,实现效果为从 T 中提取 T 与 U 的交集类型。示例代码如下:
type extract0 = Extract // number
type extract1 = Extract<'a' | 'b' | 'c', 'a' | 'c'> // 'a' | 'c
Pick
type Pick = {
[P in K]: T[P]
}
T 是多类型,K 是 T 的部分类型,然后遍历 K 拿到键,再去 T 里拿到相应的值。简单来说就是:
从 T 中提取出 T 与 K 属性值相同的属性。示例代码如下:
interface IPerson {
name: string,
age: number,
sex: string
}
type person = Pick
const user: person = {
name: 'jenny',
age: 18 // TS 提示报错,age 不在 person 类型中
}
Pick 与 Extract 都有从 T 中提取 T 与 K 相交的那部分,它们的区别在于 Pick 作用于对象类型,返回的类型用于定义对象;Extract 作用与枚举类型,返回的类型用于定义枚举类型变量。
Record
type Record = {
[P in K]: T
}
将 K 中有类型的属性进行遍历,再将每个 key 赋值为 T 类型。示例代码如下:
type record0 = Record<'a' | 'b', number>
// 相当于
// type record0 = {
// a: number,
// b: number
// }
Omit
type Omit = Pick>
实现效果为从对象 T 中剔除 key 为 K 中的属性。
interface IPerson {
name: string,
age: number,
sex: string
}
type person = Omit
// 相当于
// type person = {
// age: number,
// sex: string
// }
ReturnType
type ReturnType = T extends (...args: any[]) => infer R ? R : any;
示例代码如下:
type T1 = ReturnType<() => string> // string
type T2 = ReturnType<(s: string) => void> // void
NonNullable
type NonNullable = T extends null | undefined ? never : T;
示例代码如下:
type T = NonNullable // string | string[]