本文内容如下
泛型进阶,utility types了解与使用
如果你都有了答案,可以忽略本文章,或去TS学习地图寻找更多答案
学习资料
工具类型 utility types
utility types是ts的工具类型,它们是用泛型实现的,是泛型用法的体现
Partial
语法:Partial< Type >
构造一个所有属性的Type设置为optional的类型
简单来说:把 传入类型Type 的 key 变为 可选的
type Person = {
name: string,
age: number
}
需求:Person的属性可传可不传
let xiaoming: Partial<Person> = {}
实现原理:传入一个对象,使用keyof遍历该对象的所有key,将key变为可选的
type Partial<T> = {
[P in keyof T]?: T[P]
}
Required
语法:Required< Type >
构造一个所有属性的Type设置为Required的类型
简单来说:把 传入类型Type 的 key 变为 必需的
type Person = {
name?: string, //可选
age?: number, //可选
}
let xiaoming: Required<Person> = { name: 'tao', age: 18 } //必须要写
实现:
type Required<T> = {
[P in keyof T]-?: T[P];
}
Readonly
语法:Readonly< Type >
构造一个所有属性的Type设置为onlyRead的类型
简单来说:把 传入类型Type 的 key 变为 只读的
type Person = {
name: string,
age: number,
}
let xiaoming: Readonly<Person> = { name: 'tao', age: 18 }
xiaoming.age = 20 //赋值报错
实现:
type Readonly<T> = {
readonly [P in keyof T]: T[P];
};
Pick
语法:Pick<Type, Keys>
通过Keys从中选择一组属性来构造类型Type
简单来说:从 传入类型Type 中把 Keys 提取出来
type Person = {
name: string,
age: number
}
const PersonOnlyName = Pick<Person, 'name'> //PersonOnlyName: 'name'
实现:
type Pick<T, K extends keyof T> = {
[P in K]: T[P]
}
Record
语法:Record<Keys, Type>
构造一个对象类型,其属性键为Keys,属性值为Type,该实用程序可用于将一个类型的属性映射到另一个类型。
简单来说:将 Keys 以 Type 的类型接口呈现
实现
type Record<K extends keyof any, T> = {
[P in K]: T;
};
前置知识
type customer = { name: string, age: number }
type OneType<T, K> = K extends keyof T ? K : never
type OneTypeResult = OneType<customer, 'name'> // 'name'
// 'name' extends 'name' | 'age' ? 'name' : never
type TwoType<T, K> = K extends keyof T ? T[K] : never
type TwoTypeResult = TwoType<customer, 'name'> // string
// 'name' extends 'name' | 'age' ? customer['name'] : never
// keyof any: string | number | symbol
type threeType<K> = K extends keyof any ? K : never
type threeTypeResult = threeType<customer> // never
let count: number = 3
type threeTypeResult2 = threeType<typeof count> // number
type threeTypeResult3 = threeType<5> // 5,被当成值类型
// P in K //P是索引,用于构成可索引对象或数组
type fiveType = Record<string, customer> // [x: string]: customer; 是 对象类型
let fiveTypeResult: fiveType = {
li: { name: 'tao', age: 18 }
}
type fiveType2 = Record<number, customer> // [x: number]: customer; 是 数组类型
let fiveTypeResult2: fiveType2 = [{ name: 'tao', age: 18 }]
例子:
interface Person {
name: string,
age: number,
}
type PersonNames = 'xiaoming' | 'zhangsan';
type PersonGroup = Record<PersonNames, Person>
let personGroup: PersonGroup = {
xiaoming: {
name: 'xiaoming',
age: 18
},
zhangsan: {
name: 'zhangsan',
age: 20
}
}
例子2:数据扁平化:将数组变成对象
const goodSymid = Symbol('goodid')
interface Goods {
[goodSymid]: number
name: string
price: number
}
const goodList: Goods[] = [
{ [goodSymid]: 101, name: '食物种子', price: 5 },
{ [goodSymid]: 102, name: '蚂蚁城堡', price: 88 },
{ [goodSymid]: 103, name: '工匠收获蚁', price: 20 },
]
let goodResult: Record<number, Goods> = {}
goodList.forEach((good) => {
goodResult[good[goodSymid]] = good
})
console.log(goodResult);
for (let goodid in goodResult) {
console.log(goodResult[goodid])
}
Exclude
语法:Exclude<Type, ExcludedUnion>
通过从Type可分配给的所有联合成员中排除来构造类型ExcludedUnion
简单来说:删除不要的属性,从 Type 中 删除ExcludedUnion 的属性,其他提取出来,如果Type中没有,就全部提取出来
type Person = {
name: string,
age: number,
sex: string,
}
type PersonKeys = keyof Person //PersonKeys: 'name' | 'age'
type Age = Exclude<PersonKeys, 'name' | 'sex'> //'age'
type All = Exclude<PersonKeys, 'xxx'> //'name' | 'age' | 'sex'
type All2 = Exclude<PersonKeys, 'xxx' | 'age'> //'name' | 'sex'
实现:
type Exclude<T, U> = T extends U ? never : T;
Extract
语法:Extract<Type, ExcludedUnion>
通过从Type可分配给的所有联合成员中提取来构造类型Union
实现
type Extract<T, U> = T extends U ? T : never;
类的用法
定律1:子类 extends 父类, 就一定返回true,返回T类型
定律2:父类 extends 子类, 一般返回false,返回never,如果父类属性和方法 和 子类一样,就返回true,返回T类型
class People {
constructor(public name: string, public age: number) { }
}
class ChinesePeople extends People {
public phone!: number
}
// 定律:子类 extends 父类, 就一定返回true,返回T类型
type peopleType = Extract<ChinesePeople, People> //ChinesePeople
// 定律:父类 extends 子类, 一般返回false,返回never,如果父类属性和方法 和 子类一样,就返回true,返回T类型
type peopleType2 = Extract<People, ChinesePeople> //never
函数类型用法
和类的使用方法一样,对比参数个数,类型,返回值是否和第二个参数相同或子集
type fn1 = (name: string, age: number) => any
type fn2 = (name: string) => string
type result = Extract<fn2, fn1> //(name: string) => string
fn2的参数name:string,返回string,fn1同样有name:string,返回any,只要修改类型,或者参数个数,或者返回值类型,导致两个函数不同,就会返回never
联合类型用法
简单来说:提取要的属性,从 Type 中 提取ExcludedUnion 的属性,如果都没有,就都不提取,返回never
type Names = "xiaoming" | "zhangsan" | 'lisi'
type newNames = Extract<Names, 'zhangsan' | 'wangwu'> //提取'zhangsan','wangwu'第一个参数里没有,所以不提取
type newNames = Extract<Names, 'wangwu'> //never
Omit
语法:Omit<Type, Keys>
通过从中选择所有属性Type然后删除Keys来构造类型
简单来说:删除不要的属性
type Person = {
name: string,
age: number,
gender: string,
}
需求:只要Person的某个属性,删除不要的属性,不修改原有Person
let xiaoming: Omit<Person, 'name' | 'age'> = { gender: '男' }
Omit的实现:
type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>
NonNullable
语法:NonNullable< Type >
简单来说:过滤类型中的 null 及 undefined 类型。
type Names = "xiaoming" | undefined | null
type newNames = NonNullable<Names> //"xiaoming"
实现:
type NonNullable<T> = T extends null | undefined ? never : T;
ReturnType
语法:ReturnType< FnType >
简单来说:获取函数的返回值类型
const fn = (): string => 'tao'
type RootState = ReturnType<typeof fn>
const x: RootState = 'tao'
Parameters
语法:Parameters< FnType >
从函数类型的参数中使用的类型构造一个元组类型Type
简单来说:以元组类型的方式,获得函数的参数类型
const fn = (name: string, age: number): void => console.log(name, age);
type A = Parameters<typeof fn> // [name: string, age: number]
type B = Parameters<() => void> //[]
实现:使用infer
type Parameters<T extends (...args: any) => any> = T extends (...args: infer P) => any ? P : never;
学习更多