泛型进阶:工具类型utility types

本文内容如下

泛型进阶,utility types了解与使用

如果你都有了答案,可以忽略本文章,或去TS学习地图寻找更多答案


学习资料

官网utility types


工具类型 utility types

utility types是ts的工具类型,它们是用泛型实现的,是泛型用法的体现


Partial

语法:Partial< Type >

构造一个所有属性的Type设置为optional的类型

简单来说:把 传入类型Typekey 变为 可选的

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的类型

简单来说:把 传入类型Typekey 变为 必需的

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的类型

简单来说:把 传入类型Typekey 变为 只读的

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,该实用程序可用于将一个类型的属性映射到另一个类型。

简单来说:将 KeysType 的类型接口呈现

实现

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;

学习更多

TS学习地图

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值