msa*_*ord 2 generics ecmascript-5 typescript ecmascript-6 typescript2.0
我经常必须按属性对对象进行排序,因此我编写了以下简单的帮助程序:
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;
});
Run Code Online (Sandbox Code Playgroud)
我经常必须按对象上类似日期的属性对对象进行排序,但是我收到的日期是以格式进行字符串化的"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;
});
Run Code Online (Sandbox Code Playgroud)
导致
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;
}
Run Code Online (Sandbox Code Playgroud)
但是在我的排序比较器中,它从中lib.es2015.core.d.ts
选择接口,该接口只有:
interface DateConstructor {
new (value: Date): Date;
}
Run Code Online (Sandbox Code Playgroud)
尝试断言无效new Date(a[field] as string)
或as Date
无效。
我正在使用TypeScript 2.7.2(当前的Angular 6.0.9项目要求该属性,并且不能更改)。
所以:
tsc
在这种情况下为什么要选择一个呢?
如何断言我要使用哪个代码,或者至少在维护field: keyof T
参数的同时让我的代码编译?
我目前无法在2.7.2上进行测试,但是主要问题是TypeScript认为a[field]
不一定是string
。这是有道理的,因为a
是通用类型的T
,而且field
是类型的keyof T
,所以它所知道的a[field]
是T[keyof T]
。这可能是string
,也可能是东西,你不能打电话new Date()
的。
如果您确定只能byDate
在a[field]
a 上调用string
,则可以将泛型更改为:
static byDate = <K extends keyof any, T extends Record<K, string>>(
list: Array<T>,
field: K,
descending: boolean = true
) => { ... }
Run Code Online (Sandbox Code Playgroud)
那应该使错误消失……它现在知道a[field]
类型是type T[K]
,其中T
extends Record<K, string>
也称为{[P in K]: string}
,或者是“其键在其中K
且值是string
”的对象。如此T[K]
扩展string
,它很高兴。
上述应在打字稿2.7.2工作,但让我知道如果你遇到了一个问题。
希望能有所帮助。祝好运!