TypeScript 泛型函数重载和/或类型保护
我正在尝试创建一个通用函数,以这种方式提取枚举和对象的键和值:
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]);
}
问题是,无论 anything 的键是什么,Object.keys(anything) 都返回 string[],更糟糕的是,当 anything 是一个枚举时,它还会将数值作为字符串返回(在我看来这显然是错误的),所以我为这种情况写了一个特定的函数:
function keys(record: Enum): Array<number> {
return Object.keys(record)
.map((x) => parseInt(x))
.filter((x) => !isNaN(x));
}
现在我该如何将这段代码合并到通用键函数中呢?我猜可以在 K 上加一个类型保护,以防它是数字,但我尝试了很多方法都没有成功……
顺便问一下,有没有已经实现这个功能的“纯 TypeScript”库?
答案#1
这并不直观——但实际上假设 keyof T 来自 Object.keys 是不正确的——完整解释请参见 https://stackoverflow.com/a/55012175/2310450 ——但简而言之,需要记住 TypeScript 不会执行对象的额外属性检查,并且可能存在运行时原型污染的问题。
如果我理解你的问题正确的话——我相信你可以在你的过滤语句中使用 Extract
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)[]
