内置工具类型
一、Omit
Omit基于已经声明的类型进行属性剔除获得新类型
原理
type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;
语法
type GoodType = {
id:number;
name:string;
price:number;
description:string;
}
const good:Omit<GoodType,'description'> = {
id:888,
name:'哈哈哈',
price:6300
}
二、Pick
Pick 能够帮助我们从传入的属性中摘取某些返回
原理
type Pick<T, K extends keyof T> = {
[P in K]: T[P];
}
语法
type GoodType = {
id: number;
name: string;
price: number;
count: number;
}
const good: Pick<GoodType, 'id' | 'name'> = {
id: 1,
name: '哈哈哈哈'
}
应用场景
-
Pick 与 Record 的搭配使用---相当于对 map 进行校验
type GoodType = {
id: number;
name: string;
price: number;
description: string;
}
const goodList: GoodType[] = [
{
id: 1,
name: '哈哈',
price: 6300,
description: '开机开卷考'
}
]
let goodListFilter: Record<number, Pick<GoodType, 'id' | 'name'>> = {}
goodListFilter = goodList.map((value) => {
const obj = {
id: value.id,
name: value.name
}
return obj;
})
console.log(goodListFilter)
三、Record
Record<K,T>
构造一个类型,该类型具有一组属性 K,每个属性的类型为 T。可用于将一个类型的属性映射为另一个类型。Record 后面的泛型就是对象键和值的类型。
简单理解:K 对应对应的 key,T 对应对象的 value,返回的就是一个声明好的对象 但是 K 对应的泛型约束是keyof any 也就意味着只能传入 string|number|symbol
原理
type Record <K extends keyof any,T> = {
[P in K] : T
}
// 理解一:
type Record <string extends string | number | symbol,T> = {
[P in string]: T
}
// 理解二:
type Record <string|number extends string | number | symbol,T> = {
[P in string|number]: T
}
// 理解二:
type Record <string|number|symbol extends string | number | symbol,T> = {
[P in string|number|symbol]: T
}
type Record<T> = {
[P in keyof any]: T;
}
语法
-
K 为任意字符串,那么类型最终为对象
type TypeA = "x" | "y";
type TypeB = Record<TypeA, { name: '柏拉图', age: 23 }>
const map: TypeB = {
x: { name: '柏拉图', age: 23 },
y: { name: '柏拉图', age: 23 }
} -
K 为 number,那么生成的类型可以为对象数组
type TypeB = Record<number, { name: '柏拉图', age: 23 }>
const map: TypeB = {
0: { name: '柏拉图', age: 23 },
1: { name: '柏拉图', age: 23 }
}
// 等效于:
type TypeB = Record<number, { name: '柏拉图', age: 23 }>
const map: TypeB = [
{ name: '柏拉图', age: 23 },
{ name: '柏拉图', age: 23 }
]
使用场景
-
通过 Record 完成数据扁平化
-
当 K 为 number 时:
[P in number]
type GoodType = {
id: number;
name: string;
price: number;
}
const goodList: GoodType[] = [
{
id: 1,
name: 'MacBook Pro',
price: 26400
},
{
id: 2,
name: 'Iphone13 Pro Max',
price: 9700
}
]
const goodListMap: Record<number, GoodType> = {}
goodList.forEach(item=>{
goodListMap[item.id] = item;
})
console.log(goodListMap) -
当 K 为 string 时:
[P in string]
,如果 P 为 number 类型,那么最终也是会转化成 string 的,所以[P in string]
也是成立的type GoodType = {
id: number;
name: string;
price: number;
}
const goodList: GoodType[] = [
{
id: 1,
name: 'MacBook Pro',
price: 26400
},
{
id: 2,
name: 'Iphone13 Pro Max',
price: 9700
}
]
const goodListMap: Record<string, GoodType> = {}
goodList.forEach(item=>{
goodListMap[item.id] = item;
})
console.log(goodListMap)
-
-
Pick 与 Record 的搭配使用---相当于对 map 进行校验
type GoodType = {
id: number;
name: string;
price: number;
description: string;
}
const goodList: GoodType[] = [
{
id: 1,
name: '哈哈',
price: 6300,
description: '开机开卷考'
}
]
let goodListFilter: Record<number, Pick<GoodType, 'id' | 'name'>> = {}
goodListFilter = goodList.map((value) => {
const obj = {
id: value.id,
name: value.name
}
return obj;
})
console.log(goodListFilter)
问题
-
object
、Map
和Record
区别?- object 可以赋值初始值
{}
,但是再次赋值时或出现错误; object 没有自动提示功能
const obj:object = {};
obj['name'] = '呵呵' // Element implicitly has an 'any' type because expression of type '"name"' can't be used to index type '{}'.Property 'name' does not exist on type '{}'.ts(7053)- Record 获取到的是索引参数类型,所以可以赋值初始值为
{}
; Record 是泛型,获取值时有自动提示功能; Record 相比 Map 更加轻量,没有必要用 Map; Record 自己实现也很方便,而且有两种实现方式,可以将 Record 改成只需要声明一个 泛型的 实现。
const obj:Record<number,{name:'呵呵'}> = {}
obj[2] = {name:'呵呵'}- Map 相对 Record 是重量级的,更加占用内存空间; 但是如果增删改次数较多,那么用 Map 还是较好的; Map 需要声明两个泛型,如果要改成一个泛型需要改动底层源码,自己实现是很难的
- object 可以赋值初始值
四、Extract
Extract<T,U>
T 是否继承 U,如果T继承U,返回T类型,否则返回never
原理
type Extract<T, U> = T extends U ? T : never;
语法
-
接口使用 Extract
-
接口继承
interface PersonType {
name:string;
age:number;
}
interface ChinesePersonType extends PersonType{
sex:string;
}
const number:Extract<ChinesePersonType,PersonType> = {
name:'呵呵',
age:23,
sex:'男'
};
// 等效于
ChinesePersonType extends PersonType ? ChinesePersonType : never -
接口 keyof: 获取 A 和 B 中的共有 key
interface TypeA {
name: string;
age: number;
}
interface TypeB {
name: string;
age: number;
sex: string;
}
type Type = Extract<keyof TypeB, keyof TypeA>;
-
-
联合类型使用 Extract: 联合类型要分开比较,
a|b,c|d
的结果等效于a extends c|d
|b extends c|d
的结果const a: Extract<string | number, number> = 3;
// 等效于
string extends number ? string : never; // never
number extends number ? number : never; // number
// 所以结果为: number | never = number -
函数 使用 Extract: 函数返回类型、参数类型完全相同的情况下,参数少的函数类型
extends
参数多的函数类型 返回true
;参数多的函数类型extends
参数少的函数类型 返回false
;type Fun1Type = (name:string,age:number) => string;
type Fun2Type = (name:string) => string;
type FunType = Extract<Fun2Type,Fun1Type>;
五、Exclude
Exclude<T,U>
T 是否继承 U,如果T继承U,返回 never,否则返回 T 类型
原理
type Exclude<T, V> = T extends V ? never : T;
语法
-
接口使用 Exclude
-
接口继承
interface PersonType {
name:string;
age:number;
}
interface ChinesePersonType extends PersonType{
sex:string;
}
const number:Exclude<PersonType,ChinesePersonType> = {
name:'呵呵',
age:23,
};
// 等效于
PersonType extends ChinesePersonType ? never : PersonType // PersonType -
接口 keyof: 从 B 中获取 A 中所没有的 key
interface TypeA {
name: string;
age: number;
}
interface TypeB {
name: string;
age: number;
sex: string;
}
type Type = Exclude<keyof TypeB, keyof TypeA>;
-
-
联合类型使用 Exclude: 联合类型要分开比较,
a|b,c|d
的结果等效于a extends c|d
|b extends c|d
的结果const a: Exclude<string | number, number> = '哈哈哈';
// 等效于
string extends number ? never : string; // string
number extends number ? never : number; // never
// 所以结果为: string | never = string -
函数 使用 Exclude: 函数返回类型、参数类型完全相同的情况下,参数少的函数类型
extends
参数多的函数类型 返回true
;参数多的函数类型extends
参数少的函数类型 返回false
;type Fun1Type = (name: string, age: number) => string;
type Fun2Type = (name: string) => string;
type FunType = Exclude<Fun1Type, Fun2Type>;
六、Partial
Partial可以将传入的属性由非可选变为可选
原理
type Partial<T> = {
[P in keyof T]?: T[P]
}
语法
type GoodType = {
id:number;
name:string;
price:number;
discription:string;
}
const good:Partial<GoodType> = {
id:1,
name:'哈哈哈哈'
}
七、Required
Required可以将传入的属性中的可选项变为必选项,这里用了 -?
修饰符来实现。
原理
type Required<T> = {
[P in keyof T]-?: T[P]
}
语法
type GoodType = {
id:number;
name:string;
price?:number;
discription?:string;
}
const good:Required<GoodType> = {
id:1,
name:'哈哈哈哈',
price:6300,
discription:'我是商品'
}
八、Readonly
Readonly通过为传入的属性每一项都加上 readonly 修饰符来实现。
原理
type Readonly<T> = {
readonly [P in keyof T]: T[P];
}
语法
type GoodType = {
id:number;
name:string;
price:number;
description:string;
}
const good:Readonly<GoodType> = {
id:888,
name:'哈哈哈',
price:6300,
description:'激将法低价'
}
good.id = 333; // 报错 Cannot assign to 'id' because it is a read-only property
九、NonNullable
NonNullable 从 T 中排除 null 和 undefined
type NonNullable<T> = T extends null | undefined ? never : T;
type E = NonNullable<string | number | null | undefined>;
let e: E = null;
十、ReturnType
ReturnType 主要是获取函数类型的返回类型
type ReturnType<T extends (...args: any[]) => any> = T extends (
...args: any[]
) => infer R
? R
: any;
function getUserInfo() {
return { name: "hello", age: 10 };
}
// 通过 ReturnType 将 getUserInfo 的返回值类型赋给了 UserInfo
type UserInfo = ReturnType<typeof getUserInfo>;
const userA: UserInfo = {
name: "hello",
age: 10,
};
十一、Parameters
Parameters 该工具类型主要是获取函数类型的参数类型
type Parameters<T> = T extends (...args: infer R) => any ? R : any;
type T0 = Parameters<() => string>; // []
type T1 = Parameters<(s: string) => void>; // [string]
type T2 = Parameters<<T>(arg: T) => T>; // [unknown]