[英]Generic with indexed argument of type in typescript
我想要一个通用的,我可以在保留输入的同时按名称索引。 能够编写以下代码会很有用:
candidates.sort(compareByClosestTo("recieved", date))
我感觉很接近,但似乎无法完成这个
// generic comparison fn with index
type Dateable<T> = {
[P in keyof T]: DateTime
};
const compareByClosestTo = <T extends Dateable<T>>(key: keyof T, date: DateTime) =>
(l: T, r: T) => Math.abs(l[key].diff(date).milliseconds) - Math.abs(r[key].diff(date).milliseconds)
但是这会产生错误,因为它要求所有参数都是 DateTime 类型。 有没有办法简单地限制 T[key] 的类型?
编辑
发布此消息 5 分钟后,我在这里遇到了一个提示,导致我:
function sortByClosest<K extends string>(data: Record<K, DateTime>[], key: K, date: DateTime): void {
data.sort((l, r) =>
Math.abs(l[key].diff(date).milliseconds) - Math.abs(r[key].diff(date).milliseconds))
}
但是,我想保持开放状态,因为我真的很想知道如何计算回调工厂的类型化通用索引(即,顶级 forms 可能吗?)
我认为您原来的compareByClosestTo()
function 的主要问题是T
没有好的推理站点。 key
参数的类型为keyof T
。 如果您为key
传入"foo"
,则需要编译器推断类型T
,其中"foo"
是其键之一。 编译器可能会推断出{foo: DateTime}
,具体取决于您如何使用它,或者它可能会放弃并推断出类似{foo: any}
甚至{[k: string]: any}
的东西。 您唯一可以期望编译器可靠地从"foo"
类型的值推断出的是字符串"foo"
本身。
为此,让我们放弃T extends Dateable<T>
,而是看看K extends PropertyKey
。 然后我们可以用K
来表示T
:在这种情况下, { [P in K]: DateTime }
等价于Record<K, DateTime>
(使用Record
实用程序类型):
const compareByClosestTo = <K extends PropertyKey>(key: K, date: DateTime) =>
(l: { [P in K]: DateTime }, r: { [P in K]: DateTime }) =>
Math.abs(l[key].diff(date).milliseconds) - Math.abs(r[key].diff(date).milliseconds);
让我们看看当我们调用它时会发生什么:
const compareFn = compareByClosestTo("recieved", DateTime.local());
/* const compareFn: (l: {
recieved: DateTime;
}, r: {
recieved: DateTime;
}) => number */
在这里, K
被推断为"received"
,结果比较 function 是我们想要的{received: DateTime}
类型。 因此,以下两个sort()
调用都有效:
const works = dates.map(dt => ({ recieved: dt }))
.sort(compareByClosestTo("recieved", DateTime.local()))
const stillWorks = dates.map((dt, i) => ({ recieved: dt, index: i }))
.sort(compareByClosestTo("recieved", DateTime.local()))
因为您正在排序的每个 arrays 都有可分配给{received: DateTime}
的元素。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.