泛型:TS2345类型'T [keyof T]'的参数不能分配给类型'Date'的参数,其中<t extended =“” {} =“”>

时间:2018-07-31 20:05:47

标签: typescript generics ecmascript-6 typescript2.0 ecmascript-5

我经常必须按属性对对象进行排序,因此我编写了以下简单的帮助程序:

static sort = <T extends {}>(list: Array<T>, field: keyof T, descending: boolean = true) =>
  list.sort((a, b) => {
    if (a[field] > b[field]) {
      return descending ? -1 : 1;
    }
    if (a[field] < b[field]) {
      return descending ? -1 : 1;
    }
    return 0;
  });

我经常不得不通过对象上类似日期的属性对对象进行排序,但是我收到的日期以"01-Apr-2018"的格式进行字符串化,因此我必须先将它们转换为日期。

因此,我用以下内容扩展了上述内容:

static byDate = <T extends {}>(list: Array<T>, field: keyof T, descending: boolean = true) =>
  list.sort((a, b) => {
    if (new Date(a[field]).getTime() > new Date(b[field]).getTime()) {
      return descending ? -1 : 1;
    }
    if (a[field] < b[field]) {
      return descending ? 1 : -1;
    }
    return 0;
  });

这将导致

  

TS2345:类型“ T [keyof T]”的参数不能分配给类型“ Date”的参数

a[field]b[field]上。

跟踪选择的WebStorm / TypeScript Service的Date实现,我注意到在new Date("hello")中,它从lib.es5.d.ts中选择以下接口:

interface DateConstructor {
    new(): Date;
    new(value: number): Date;
    new(value: string): Date; // THIS ONE (which I expect)
    new(year: number, month: number, date?: number, hours?: number, minutes?: number, seconds?: number, ms?: number): Date;
    (): string;
    readonly prototype: Date;
    parse(s: string): number;
    UTC(year: number, month: number, date?: number, hours?: number, minutes?: number, seconds?: number, ms?: number): number;
    now(): number;
}

但是在我的排序比较器中,它选择the interface from lib.es2015.core.d.ts,它只有:

interface DateConstructor {
    new (value: Date): Date;
}

尝试使用new Date(a[field] as string)as Date进行声明无效。

我正在使用TypeScript 2.7.2(我当前的Angular 6.0.9项目要求该属性,并且不能更改)。

所以:

  1. 在这些情况下,tsc为什么要选择一个呢?

  2. 如何确定要使用的代码,或者至少在保持field: keyof T参数的情况下使我的代码编译?

1 个答案:

答案 0 :(得分:4)

我目前无法在2.7.2上进行测试,但是主要的问题是TypeScript认为a[field]不一定是string。这是有道理的,因为a的类型为T,而field的类型为keyof T,所以所知道的是a[field]是{{1 }}。 可能T[keyof T],或者您可能无法调用string

如果您确定只在new Date()byDate的地方调用a[field],则可以将泛型更改为:

string

那应该使错误消失……它现在知道static byDate = <K extends keyof any, T extends Record<K, string>>( list: Array<T>, field: K, descending: boolean = true ) => { ... } 是类型a[field],其中T[K]扩展了T,也称为{{1} },或“其键在Record<K, string>中且其值是{[P in K]: string}的对象”。因此K扩展了string,很高兴。

上面的应该可以在TypeScript 2.7.2上运行,但是如果遇到问题,请告诉我。

希望有帮助。祝你好运!