代码之家  ›  专栏  ›  技术社区  ›  ford04

使用array reduce方法使用条件类型和映射类型

  •  0
  • ford04  · 技术社区  · 6 年前

    我想实现一个通用的 sum 方法通过 Array.prototype.reduce

    总和

    • 它的一个属性限制为 number 返回值

    我的企图是利用 conditional and mapped types 在这里:

    类型定义:

    type MeasureableEntityPropNames<E> = 
       { [K in keyof E]: E[K] extends number ? K : never }[keyof E];
    type MeasurableEntity<E> = Pick<E, MeasureableEntityPropNames<E>>;
    
    type MyEntity = {
        p1: number,
        p2: string,
        p3: Date,
        p4: number
    };
    

    let entities: MyEntity[] = [
        { p1: 1, p2: "str", p3: new Date(), p4: 3 },
        { p1: 2, p2: "str2", p3: new Date(), p4: 1 }
    ]
    

    求和方法和调用:

    const sum = <E>(elements: MeasurableEntity<E>[], prop: keyof MeasurableEntity<E>) =>
        elements.reduce((acc: number, cur: MeasurableEntity<E>) => {
            return acc + cur[prop]; // ERROR
        }, 0);
    
    sum<MyEntity>(entities, "p1");
    

    错误:

    运算符“+”不能应用于类型“number”和“Pick[{[K in keyof”

    类型定义是否有问题,或者类型脚本无法推断 cur[prop] 属于类型 ? 这里要换什么?

    问候语

    1 回复  |  直到 6 年前
        1
  •  2
  •   Titian Cernicova-Dragomir    6 年前

    虽然约束键的方法对调用者很有效,但函数Typescript内部将无法确定键指定的字段始终是数字,因为在这种情况下,在知道类型参数之前,不会计算条件类型。

    通过将键用作泛型类型参数并指定传入的数组必须是一个记录,而作为类型参数传入的键必须是一个数字,我们可以轻松地解决这个问题。当然,我们可以指定一个具有更多键的实体作为参数,但是作为第二个参数传入的键必须指向一个数字字段

    const sum = <K extends string>(elements: Record<K, number>[], prop: K) =>
        elements.reduce((acc: number, cur) => {
            return acc + cur[prop];      
        }, 0);
    
    type MyEntity = {
        p1: number
        p2: string,
        p3: Date,
        p4: number
    };
    let entities: MyEntity[] = [
        { p1: 1, p2: "str", p3: new Date(), p4: 3 },
        { p1: 2, p2: "str2", p3: new Date(), p4: 1 }
    ]
    sum(entities, "p1");
    sum(entities, "p2"); //Error