【问题标题】:Use of Conditional types and mapped types with array reduce method使用数组 reduce 方法使用条件类型和映射类型
【发布时间】:2019-01-18 17:56:43
【问题描述】:

我想通过Array.prototype.reduce 实现一个通用的sum 方法,该方法总结了实体的特定数字属性。

sum 应该接受两个参数:

  • 通用实体类型 E
  • 它的一个属性限制为 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 }
]

sum 方法和调用:

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 E]: E[K] 扩展数? K:从不; }[keyof E]]'。

类型定义有问题还是打字稿不能推断cur[prop]number 类型?这里要改什么?

问候

(打字稿 3.0.1)

【问题讨论】:

    标签: typescript


    【解决方案1】:

    虽然您约束键的方法对调用者很有效,但在函数内部,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
    

    【讨论】:

    • 完美运行。感谢评估条件类型时的解释!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-10-26
    • 2021-02-20
    • 2019-03-21
    • 2018-03-02
    • 1970-01-01
    • 2018-06-25
    • 2018-02-05
    相关资源
    最近更新 更多