我正在TypeScript中创建一个通用的排序模块. 其中一个接收一个数据对象数组,然后一个要排序的键列表,一旦完成数组,将按照键列表中指定的键排序.
首先,我会做这两种类型:
export type Comparer<T>: (a: T, b: T) => number;
export type SortKey<T> = {
key: keyof T,
order: 'ascending' | 'descending',
comparer: Comparer<T[keyof T]>
};
上面的测试结果是有问题的. 让我们看一个例子:
// numberComparer is of type (a: number, b: number) => number
import { numberComparer } from 'somewhere';
type Person = {
id: number;
name: string;
};
const sortKey: SortKey<Person> = {
key: 'id',
order: 'ascending',
comparer: numberComparer
};
这显示了一个TS错误:comparer
属性是Comparer<string | number>
类型,但numberComparer
不是.发生这种情况是因为类型无法推断,因为key
的值是'id'
,所以它将比较数字,因为id
是数值字段.
所以v2的类型:
export type SortKey<T, K extends keyof T = keyof T> = {
key: K,
order: 'ascending' | 'descending',
comparer: Comparer<T[K]>
};
在此版本中,如果我们显式指定K
,则该示例将起作用.就我个人而言,我认为TS应该能够推断出它,但不管怎样:
const sortKey: SortKey<Person, 'id'> = {
key: 'id',
order: 'ascending',
comparer: numberComparer
};
错误现在消失了. 然而,我们面临另一个问题. 一般的sort
函数看起来像这样:
export function sort<T>(data: T[], keys: SortKey<T>[]);
编写函数体不会产生错误,因此这适用于函数体. 但是,函数的consumer不能做这样的事情:
const myKeys: SortKey<Person>[] = [
{
key: 'id',
order: 'descending',
comparer: numberComparer
},
{
key: 'name',
order: 'ascending',
comparer: stringComparer
}
];
上面的错误抛出了最初看到的TS错误,其中给定的比较器是用于特定类型(数字或字符串),但comparer
属性接受Person
类型中的所有键范围.
一种解决方法是创建一个所需类型的"主"比较器,其实现将对参数进行类型判断,然后相应地调用特定的比较器. 很丑.
那么,我的打字员们,有什么解决办法吗? 一如既往,我感激你.