Typescript一些常用的泛型工具

2,975 阅读4分钟

前言

本文将简要介绍Typescript一些常用泛型工具的使用技巧以及其相应的实现原理,进行相应的总结,如有不对之处,还望指出,感谢支持。

Typescript泛型工具

  • Partial

    将传入的属性变为可选项

    interface IPeople {
        title: string;
        name: string;
    }
    
    const people: Partial<IPeople> = {
        title: 'Delete inactive users'
    };
    

    实现原理:

    将映射对象类型 { P in K : T } 与索引类型 keyof T 查询结合使用来遍历已有对象类型的所有属性成员, 再对其属性成员设为可选属性。

    interface IPeople {
        title: string;
        name: string;
    }
    
    type MyPartial<T> = {
        [P in keyof T]?: T[P];
    };
    
    const people: MyPartial<IPeople> = {
        title: 'Delete inactive users'
    };
    
  • Record<K, T>

    类型参数K提供了对象属性名联合类型,类型参数T提供了对象属性的类型

    interface Person {
      name: string;
    }
    
    // 将x, y 作为Person的key
    type Peoples = Record<"x" | "y", Person>;
    
    const P: Peoples = {
        x: {
            name: '张三'
        },
        y: {
            name: '李四'
        }
    }
    

    实现原理:

    通过 K extends keyof any 对泛型进行约束,约束在 any 的 key中, K可以是任意类型(联合类型、对象、枚举…),再通过映射对象类型 { P in K : T } ,将每一个属性成员转化为 T 类型

    interface Person {
      name: string;
    }
    
    type MyRecord<K extends keyof any, T> = {
      [P in K]: T;
    };
    
    // 将x, y 作为Person的key
    type Peoples = MyRecord<"x" | "y", Person>;
    
    const P: Peoples = {
      x: {
        name: "张三",
      },
      y: {
        name: "李四",
      },
    };
    
  • Readonly

    把传入的类型变为只读状态

    interface Person {
      name: string;
      age: number;
    }
    
    const p: Readonly<Person> = {
        name: '张三',
        age: 22
    }
    
    p.name = '李四'; // 无法分配到 "name" ,因为它是只读属性
    

    实现原理:

    Partial 实现原理类似,通过映射对象类型 { P in K : T } 方式遍历获取其所有属性成员,再统一设置为 readonly

    interface Person {
      name: string;
      age: number;
    }
    
    type MyReadonly<T> = {
      readonly [P in keyof T]: T[P];
    };
    
    const p: MyReadonly<Person> = {
      name: "张三",
      age: 22,
    };
    
    p.name = "李四"; // 无法分配到 "name" ,因为它是只读属性
    
  • Required

    把传入的类型变为必填状态

    interface Person {
        name?: string;
        age?: number;
    }
    
    const p: Required<Person> = {
        name: '张三',
        age: 22
    }
    

    实现原理:

    Partial 实现原理类似,通过映射对象类型 { P in K : T } 方式遍历获取其所有属性成员, 再统一通过“-” 修饰符移除 “?” 修饰符,从而转变为必填状态

    interface Person {
        name?: string;
        age?: number;
    }
    
    type MyRequired<T> = {
        [P in keyof T]-?: T[P];
    };
    
    const p: MyRequired<Person> = {
        name: '张三',
        age: 22
    }
    
  • Pick<T, S>

    在 T 中,过滤掉非 S 的类型

    interface IPerson {
        name: string;
        age: number;
    }
    
    type TP = Pick<IPerson, 'name'>;
    
    const p: TP = {
        age: 22, // 对象文字可以只指定已知属性,并且“age”不在类型“TP”中
        name: '张三'
    }
    

    实现原理:

    通过 K extends keyof T 进行泛型约束,将 K 被约束在 T 的key中,不能超出这个范围,再通过映射对象类型 { key in K : T[key] } ,来约束每一个属性成员。

    interface IPerson {
        name: string;
        age: number;
    }
    
    type MyPick<T, K extends keyof T> = {
    	[key in K]: T[key]
    }
    
    type TP = MyPick<IPerson, 'name'>;
    
    const p: TP = {
        age: 22, // 对象文字可以只指定已知属性,并且“age”不在类型“TP”中
        name: '张三'
    }
    
  • Exclude<T, U>

    该工具类型能够从类型T中剔除所有可以赋值给类型U的类型

    type T0 = Exclude<"a" | "b" | "c", "a">;
    // 相当于 type T0 = "b" | "c"
    
    type T1 = Exclude<"a" | "b" | "c", "a" | "b">;
    // 相当于 type T1 = "c"
    
    type T2 = Exclude<string | number | (() => void), Function>;
    // 相当于 type T2 = string | number	
    

    实现原理:

    表示如果 TU 的子类返回 never 类型,如果不是返回 T 类型。 当 T 为联合类型的时候,它会自动分发条件。

    type MyExclude<T, U> = T extends U ? never : T;
    
    type T0 = MyExclude<"a" | "b" | "c", "a">;
    // 相当于 type T0 = "b" | "c"
    
    type T1 = MyExclude<"a" | "b" | "c", "a" | "b">;
    // 相当于 type T1 = "c"
    
    type T2 = MyExclude<string | number | (() => void), Function>;
    // 相当于 type T2 = string | number
    
  • Extract<T, U>

    “Extract<T, U>”工具类型与“Exclude<T, U>”工具类型是互补的,它能够从类型T中获取所有可以赋值给类型U的类型

    type T0 = Extract<'a' | 'b' | 'c', 'a' | 'f'>;
    // 相当于 type T0 = 'a';
    
    type T1 = Extract<string | (() => void), Function>;
    // 相当于 type T1 = () => void;
    
    type T2 = Extract<string | number, boolean>;
    // 因为没有交集,相当于 type T2 = never;
    

    实现原理:

    Exclude<T, U> 实现方式类似

    type MyExtract<T, U> = T extends U ?  T : never;
    
    type T0 = Extract<'a' | 'b' | 'c', 'a' | 'f'>;
    // 相当于 type T0 = 'a';
    
    type T1 = Extract<string | (() => void), Function>;
    // 相当于 type T1 = () => void;
    
    type T2 = Extract<string | number, boolean>;
    // 因为没有交集,相当于 type T2 = never;
    
  • Omit<T, K>

    在 T 中删除对应的 K

    interface IPerson {
        name: string;
        age: number;
    }
    
    type TP = Omit<IPerson, 'age'>;
    
    const p: TP = {
        name: '张三'
    }
    
  • ReturnType

    该工具类型能够获取函数类型T的返回值类型

    // string
    type T0 = ReturnType<() => string>;
    
    // { a: string; b: number }
    type T1 = ReturnType<() => { a: string; b: number}>;