• TypeScript – Pick,Partial,ReturnType类型操作


    文章转载自我自己的小破站,欢迎大佬们进来瞧一瞧

    1. Pick

    考虑下列的场景,有两个 Interface,SubState 是 State 的子集,相同字段类型相同,我们可以这样定义:

    interface State {
      field1: string;
      field2: number;
      field3: string;
    }
    
    interface SubState {
      field1: string;
      field2: number;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    可以观察到,这样的实现明显不符合 DRY(Don’t Repeat Yourself)原则。这导致一个问题,当需要修改State 接口内定义的类型时,SubState 也要同步修改,容易出错。面对这种情况,可以通过索引到 State 来消除属性的重复。

    type SubState = {
      field1: State['field1'];
      field2: State['field2'];
    }
    
    • 1
    • 2
    • 3
    • 4

    这样写解决了类型同步的问题,但是书写比较冗长。这时候可以使用一个映射类型来代替上述的写法,得到的结果是一致的。

    type SubState = {
      [k in 'field1' | 'field2']: State[k]
    }
    
    • 1
    • 2
    • 3

    映射类型在实际开发中非常常见,以至于 TypeScript 在标准库中实现了这样的类型操作,即 Pick。

    type Pick<T, K> = { [k in K]: T[k] };
    
    • 1

    对应的,SubState 可以改写成下面这种形式:

    type SubState = Pick<State, 'field1' | 'field2'>;
    // { field1: string, field2: number }
    
    • 1
    • 2

    2. Partial

    考虑下列场景,定义了一个满足接口 Options 的类,后续的更新需要限制只能接收 Options 定义的字段:

    interface Options {
      field1: string;
      field2: number;
    }
    
    interface UpdateOptions {
      field1?: string;
      field2?: number;
    }
    
    class Test {
      construct(init: Options) {};
      update(options: UpdateOptions) {};
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    同样的,可以使用一个映射类型和 keyof 从Options中创建 UpdateOptions。

    type UpdateOptions = { [k in keyof Options]?: Options[k] };
    
    • 1

    TypeScript的标准库内也有同样的实现:

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

    对应的,UpdateOptions 可以改写成下面这种形式:

    type UpdateOptions = Partial<Options>;
    
    class Test {
      construct(init: Options) {};
      update(options: UpdateOptions) {};
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    3. keyof

    如果想定义一个和一个值样子相同的类型,可以使用此方法。

    const INIT_OPTIONS = {
      field1: 1,
      field2: '2',
    }
    
    interface Options {
      field1: number;
      field2: string;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    同样的,Options 可以改写为:

    type Options = typeof INIT_OPTIONS;
    
    • 1

    4. ReturnType

    通过上面的 keyof 操作,可以为一个函数或者方法的推断返回值创建一个命名类型。

    function getDataInfo() {
      return {
        field1: 1,
        field2: '2'
      }
    }
    // 返回类型为:{ field1: number, field2: string }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    getDataInfo 的返回值的命名类型可以写成:

    type DataInfo = ReturnType<keyof getDataInfo>;
    
    • 1

    5. extends

    可以使用 extends 来约束通用类型中的参数。

    interface Options {
      field1: string;
      field2: string;
    }
    
    type IOption<T extends Options> = [T, T];
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    目前 TypeScript 要求必须在声明时明确写出通用参数,即

    const instance: IOption<Options> = [
      { field1: '1', field2: '2' },
      { field1: '3', field2: '4' }
    ];
    
    • 1
    • 2
    • 3
    • 4

    当然,也可以使用一个类型化的等身函数让 TypeScript 能够自动推断出泛型参数的类型

    const Opt = <T extends Options>(x: IOption<T>) => x;
    const instance = Opt([
      { field1: '1', field2: '2' },
      { field1: '3', field2: '4' }
    ]);
    
    • 1
    • 2
    • 3
    • 4
    • 5
  • 相关阅读:
    算法通关村-----回溯模板如何解决排列组合问题
    ALEVEL经济学:通货膨胀的原因是什么?
    mapbox 地图 生成矢量数据圆
    Node.JS后端开发笔记整理(简洁版)
    CAN(Controller Area Network)是一种用于在汽车和工业领域中进行通信的串行总线系统(附加案例)
    Java精进-手写持久层框架
    图解 paxos 论文《The Part-Time Parliament》
    【zabbix】企业微信告警
    微信小程序(一)
    每日一题day15
  • 原文地址:https://blog.csdn.net/think_A_lot/article/details/126700713