1

我有这个简单的函数来按日期对对象进行排序。但目前我必须在进行比较之前检查该字段是否真的是一个日期。在这种情况下,有没有办法限制K只允许某种类型的键Date

const compareDate = <T, K extends keyof T>(key: K) => (x: T, y: T) => {
  const v = x[key];
  const w = y[key];
  return v instanceof Date && w instanceof Date ? v.getTime() - w.getTime() : 0;
};

list.sort(compareDate('dateField'));

我想要的是:

const compareDate = <T, K extends ???>(key: K) => (x: T, y: T) => {
  // ts should know and only allow x[key] and y[key] to be of type Date here:
  return x[key].getTime() - y[key].getTime();
}

const list = [{a: 1, b: 'foo', c: new Date}];

list.sort(compareDate('a')); // <-- ts should refuse this
list.sort(compareDate('b')); // <-- ts should refuse this
list.sort(compareDate('c')); // <-- ts should allow this

有没有办法在打字稿中表达这一点

4

2 回答 2

3

您可以使用映射类型来获取Date一个类型的所有道具:

type DateProps<T> = ({ [P in keyof T]: T[P] extends Date ? P : never })[keyof T];

然后用它代替keyof T

const compareDate = <T extends Record<K, Date>, K extends DateProps<T>>(key: K) => (x: T, y: T) => {
    return x[key].getTime() - x[key].getTime();
};

借用Record@ford04 的想法,我们甚至可以确保 TypeScript 知道x[key]and的类型y[key]。这意味着instanceof函数内部不需要检查或强制转换。

操场

于 2019-09-03T11:35:17.123 回答
1

您可以使用T扩展Record<K, Date>类型来做到这一点K,该记录的一些字符串键在哪里。当您使用不指向记录内的值compareDate的 key 调用时,您会收到所需的类型错误。KDate

const compareDate = <T extends Record<K, Date>, K extends string>(key: K) => (
  x: T,
  y: T
) => x[key].getTime() - y[key].getTime();

const list = [{ a: 1, b: "foo", c: new Date() }];

list.sort(compareDate("a")); // <-- error
list.sort(compareDate("b")); // <-- error
list.sort(compareDate("c")); // <-- works!

操场

于 2019-09-03T13:07:49.093 回答