【问题标题】:Pipe transform use reduce for array of object管道变换使用减少对象数组
【发布时间】:2021-06-23 06:56:28
【问题描述】:

这是我的接口文件:

export interface ListCount {
  centre?: string;
  cause?: string;
  totalTime?: number;
}

我正在尝试通过管道变换减少对象数组:

export class SumPipe implements PipeTransform {
  transform(items: ListCount[], attr: string): number {
    return items.reduce((a, b) => a + b[attr], 0);
  }
}

在完整的 HTML 中,我希望计算总时间的总和

{{ (delayCount$ | async) | sum:'totalTime'}}

但我有这个错误:

error TS7053: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'ListCount'.

然后我将参数 attr: string 更改为 attr: keyof ListCount 仍然有这个错误:

error TS2365: Operator '+' cannot be applied to types 'number' and 'string | number'.

error TS2532: Object is possibly 'undefined'.

请帮忙

【问题讨论】:

  • 为什么attr 不是像transform(items: ListCount[], attr: number): number { 这样的数字
  • @er-sho: 因为它是属性名,它的值要被求和。
  • totalTime 是唯一可以在数组中求和的类型 (number) 时,传递它的目的是什么?以后还会有number类型的其他属性吗?
  • @er-sho:属性totalTime 中包含的值是number 类型。但在尝试使用obj['totalTime'] 访问属性的情况下,totalTime 是一个字符串。
  • 试试reduce((a:number, b:any)=>....)

标签: arrays angular typescript pipe reduce


【解决方案1】:

好的,因此您的代码编译没有问题并且可以正常工作。 Here 是一个有效的堆栈闪电战。如果它在您的本地环境中失败,也许可以尝试检查 TS 版本,尝试重新启动 Angular CLI,查找其他问题或至少提供有关确切抛出错误的行的信息。

您的代码存在一些问题。

  • 正如其他人所指出的,将任何attr 传递给管道并使用括号表示法来获取属性值是没有意义的。管道接受的唯一对象是ListCount[],所以它必须是totalTime,因为它是唯一的数字属性。如果您制作更通用的管道来接受any[],那将是有意义的。

  • 您的管道未针对您的用例进行保护。 totalTime 是一个可选属性,这意味着如果任何项目没有定义totalTime(它可以,根据您的界面),管道将返回NaN。不确定这是否是期望的行为。

【讨论】:

    【解决方案2】:

    我建议如下:

    • 限制 attr 指向数字属性
    • 考虑到属性可以是可选的。对那些使用零。
    • 或者过滤掉缺失(未定义)的值。
    export interface ListCount {
      centre?: string;
      cause?: string;
      totalTime?: number;
      otherTime?: number;
    }
    
    type NumericKeys<T> = {
        [P in keyof T]: T[P] extends number ? P : never;
    }[keyof T];
    
    
    type NumericListCountKey = NumericKeys<Required<ListCount>>;
    
    class SumPipe  {
      transform(items: ListCount[], attr: NumericListCountKey): number {
        const elemes = items.map(elem => elem[attr]);
        return elemes.reduce((prev: number, currentVal) => prev + (currentVal ? currentVal : 0), 0);
      }
    }
    
    
    // alternatively, with filter
    class SumPipe2  {
      static isNumber(n: number | undefined): n is number {
        return n != null;
      } 
    
      transform(items: ListCount[], attr: NumericListCountKey): number {
        const elems = items.map(elem => elem[attr])
                           .filter(SumPipe2.isNumber);
        return elems.reduce((prev: number, currentVal) => prev + currentVal, 0);
      }
    }
    

    Playground link

    【讨论】:

      【解决方案3】:

      根据this 文章,reduce() 有一个可选索引,它指向数组中的当前索引。知道了这一点,我会选择以下解决方案,完全忽略 attr

      return items.reduce((a, b, index) => a + b[index].totalTime, 0);
      

      【讨论】:

        猜你喜欢
        • 2019-03-26
        • 2021-06-23
        • 2018-09-03
        • 1970-01-01
        • 2020-12-30
        • 1970-01-01
        • 1970-01-01
        • 2016-12-01
        • 2018-09-01
        相关资源
        最近更新 更多