TypeScript 泛型函数重载 and/or 类型保护

TypeScript generic function overloading and/or type guard

我正在尝试使用通用函数以这种方式提取枚举和对象的键和值:

type Key = string | number | symbol;
type Dictionary<K extends Key, T> = Partial<Record<K, T>>;
type Obj = Dictionary<Key, unknown>; // stricter than object
type Enum = Dictionary<number, string>; // stricter than enum

function keys<K extends Key, T>(record: Record<K, T>): Array<K> {
  return Object.keys(record) as Array<K>;
}

function values<K extends Key, T>(record: Record<K, T>): Array<T> {
  return keys(record).map((key) => record[key]);
}

问题是 Object.keys(anything) returns string[] 无论任何东西的键是什么,更糟糕的是,当任何东西是枚举时,它 returns 也是数值作为字符串(恕我直言,这显然是错误的),所以我为这种情况编写了一个特定的函数:

function keys(record: Enum): Array<number> {
  return Object.keys(record)
    .map((x) => parseInt(x))
    .filter((x) => !isNaN(x));
}

现在如何将这段代码合并到通用键函数中?在 K 上有一个类型保护,以防它是我猜的数字,但我尝试了很多方法都没有成功...

顺便说一句,是否有一个“纯 TypeScript”库已经做到了这一点?

这不直观 - 但从 Object.keys 假设 keyof T 实际上是不正确的 - 请参阅 以获得完整解释 - 但 TLDR 是要记住 TS 不执行对象过量 属性 检查和潜在的运行时原型污染。

如果我理解你的问题 - 我相信你可以在你的过滤语句中使用 Extract 从 Enum 中提取数字键。


function keys<E extends Enum>(record: E): Extract<keyof E, number>[] {
  return Object.keys(record)
    .map((x) => parseInt(x))
    .filter((x): x is Extract<keyof E, number> => !isNaN(x));
}

const res = keys(foo); // res: (0 | 1 | 124124)[]