【问题标题】:Operator '+' cannot be applied to types 'number' and 'T[K]'运算符 '+' 不能应用于类型 'number' 和 'T[K]'
【发布时间】:2018-03-29 19:38:47
【问题描述】:

我有这个代码块:

function sumOnValue<T, K extends keyof T>(collection: Array<T>, key: K): number {
  let result = 0;
  for (const o of collection) {
    const sample = o[key];
    if (typeof o[key] === 'number') {
      result = result + sample; // [ts] Operator '+' cannot be applied to types 'number' and 'T[K]'.  red squigly line under sample.
    }
  }
  return result;
}

const sampleCharges: Array<ICharge> = [
  {
    AllowedAmount: 10,
  },
  {
    AllowedAmount: 15,
  },
  {
    AllowedAmount: 9,
  },
];

const resultedSum = sumOnValue(sampleCharges, 'AllowedAmount');
console.log(resultedSum);

如上所示,我从编译器收到错误(vscode 将其报告为问题),但是在运行代码时它很好并且没有抱怨。我应该在这里做什么来抑制错误或“通过类型检查安全地”编写此方法?

简而言之,目标是:T 数组中的给定属性相加,前提是给定属性是T 中的一个类型,并且该属性是一个数字。

【问题讨论】:

    标签: typescript


    【解决方案1】:

    在 TypeScript 2.1+ 中,这可以使用索引访问类型来完成。与类型保护不同,索引访问类型是编译时检查,永远不会进入您的 JavaScript。

    https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-1.html

    function pickAndReduce<T>(
        collection: Array<{ [k in keyof T]: number }>,
        key: keyof T
    ): number
    {
        let result = 0;
        for (const o of collection) {
            result = result + o[key];
        }
        return result;
    }
    

    如果需要,可以减少循环。

    function pickAndReduce<T>(
        collection: Array<{ [k in keyof T]: number }>,
        key: keyof T
    ): number
    {
        return collection.reduce((total, item) => total + item[key], 0);
    }
    

    编辑:

    最初我有key: string,如示例中所示,但正如评论中指出的那样,这忽略了对索引访问的类型检查。我已将其更改为 key: Key of T,因此只能使用给定对象上存在的键调用该函数。

    【讨论】:

    • 索引访问跳过类型检查
    • 这仍然不一定能完成原始代码所期望的,它只是跳过了非数字元素
    • 如果您正在编写代码以便在同一个属性中包含数字和其他内容,然后将该属性相加而忽略任何不是数字的内容,那么您可能不应该使用 TypeScript一点也不。我猜测,也许 OP 想要确保这些属性确实都是数字,而不是在运行时计算出来,因为这不是 JavaScript 可以做的。
    【解决方案2】:

    您可以使用type guard 来执行此操作——实现一个函数isNumber,它执行相同的typeof 检查:

    function isNumber(x): x is number {
        return typeof x === "number";
    }
    
    function sumOnValue<T, K extends keyof T>(collection: Array<T>, key: K): number {
      let result = 0;
      for (const o of collection) {
        const sample = o[key];
        // use here
        if (isNumber(sample)) {
          result = result + sample;
        }
      }
      return result;
    }
    

    【讨论】:

    • 这不是矫枉过正吗? OP 需要做的就是更改if 以与sample 进行比较,而不是o[key],例如:if (typeof sample === "number")。然后打字稿将适当地缩小sample的类型并且错误消失。
    • MVP!给你们俩。我完全忘记了类型警卫......这里还是新的。并感谢@CRice 的评论!!
    • 这可以使用索引访问类型而不是类型保护来完成,这是一种更简洁的方法,因为它不会向 JavaScript 添加不必要的代码。
    猜你喜欢
    • 2023-02-11
    • 1970-01-01
    • 1970-01-01
    • 2011-08-14
    • 2021-06-28
    • 1970-01-01
    • 1970-01-01
    • 2018-04-04
    • 2020-04-28
    相关资源
    最近更新 更多