ZHANGYU.dev

October 14, 2023

Typescript 工具泛型

TypeScript4.1 min to read

这些工具函数定义在lib.es5.d.ts,我的typescript版本是3.5.2

首先需要理解几个关键概念

keyof

keyoftypescript 2.1新增的关键字,keyof T返回的是T的属性名称(键名),keyof T的类型被认为是string的子类

interface Person {
    name: string;
    age: number;
    location: string;
}

type K1 = keyof Person; // "name" | "age" | "location"
type K2 = keyof Person[];  // "length" | "push" | "pop" | "concat" | ...
type K3 = keyof { [x: string]: Person };  // string

in

in可以遍历联合类型

interface User{
    name: string;
    age: number;
    phone: number;
}
type d = {
    [p in keyof User]: string;
}
// type d = {
//     name: string;
//     age: string;
//     phone: string;
// }

Mapped Types 映射类型

一个常见的任务是将一个已经存在类型中的所有属性变为可选

Person

interface Person {
    name: string;
    age: number;
    location: string;
}

它的可选属性类型应该是:

interface PartialPerson {
    name?: string;
    age?: number;
    location?: string;
}

应用映射类型,PartialPerson可以写为Person的广义转换

type Partial<T> = {
    [P in keyof T]?: T[P];
};

type PartialPerson = Partial<Person>;

Partial

Partial就是上述映射类型的举例,能够将属性转为可选属性

type Partial<T> = {
    [P in keyof T]?: T[P];
};

Required

将所有的属性转换为必选

type Required<T> = {
    [P in keyof T]-?: T[P];
};

Partial中,多了一个?,而这里是-?,它的意思是将?取掉,所以这里的每一个属性都是必选的

interface User{
    name: string;
    age?: number;
    phone: number;
}

type r = Required<User>

// type r =  {
//    name: string;
//    age: number;
//    phone: number;
// }

Readonly

将所有属性变为只读属性

type Readonly<T> = {
    readonly [P in keyof T]: T[P];
};

readonly表示只读属性,属性只能在初始化时赋值

Pick

T中取出部分属性,K是必须是T的键名的子枚举

type Pick<T, K extends keyof T> = {
    [P in K]: T[P];
};
interface User{
    name: string;
    age: number;
    phone: number;
}

type p = Pick<User,"name"|"phone">
// type p = {
//     name: string;
//     phone: number;
// }

Record

K类型转换为T类型

type Record<K extends keyof any, T> = {
    [P in K]: T;
};
interface User{
    name: string;
    age: number;
    phone: number;
}

type r = Record<keyof User, string>

// type r = {
//     name: string;
//     age: string;
//     phone: string;
// }

这里需要注意的是Record<K,T>K必须是联合类型,需要写上keyof

Exclude

T中排除U中包含的类型

type Exclude<T, U> = T extends U ? never : T;
interface User{
    name: string;
    age: number;
    phone: number;
}

type e = Exclude<keyof User, "age"|"phone">
// type e = "name"

Extract

T中提取包含U的属性

type Extract<T, U> = T extends U ? T : never;
interface User{
    name: string;
    age: number;
    phone: number;
}

type e = Extract<keyof User, "age"|"type"|"address">
// type e = "age"

Omit

构造一个类型,这个类型包含除了T类型之外的K类型的属性

type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;
interface User{
    name: string;
    age: number;
    phone: number;
}

type o = Omit<User, "age">;

// type o = {
//     name: string;
//     phone: number;
// }

NonNullable

T中去掉nullundefined

type NonNullable<T> = T extends null | undefined ? never : T;
type options = "debug" | "release" | null | undefined;

type n = NonNullable<options>;
// type n = "debug" | "release"

Parameters

获取函数中的参数类型的元组

type Parameters<T extends (...args: any) => any> = T extends (...args: infer P) => any ? P : never;
type UserFunc = (name: string, phone: number) => void

type a = Parameters<UserFunc>
// type a = [string, number]

出现了一个新关键字inferinfer可以表示extends语句中待推断的类型变量

ConstructorParameters

获取构造函数中的参数类型的元组

type ConstructorParameters<T extends new (...args: any) => any> = T extends new (...args: infer P) => any ? P : never;
class UserClass  {
    constructor(name:string,phone:number) {};
}

type a = ConstructorParameters<typeof UserClass>
// type a = [string, number]

ReturnType

获取函数返回值的类型

type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any;
type User = { name: string };
type UserFunc = () => User;

type a = ReturnType<UserFunc>
// type a = {
//     name: string;
// }

InstanceType

获取构造函数函数返回值的类型

type InstanceType<T extends new (...args: any) => any> = T extends new (...args: any) => infer R ? R : any;
class UserClass  {
    constructor(name:string,phone:number) {};
}

type a = InstanceType<typeof UserClass>
// type a = UserClass

这些内置工具函数的参数还是有一些不理解,有些是直接传类型,有些是传keyof后的联合类型,有一些又是typeof,需要加省学习