TypeScript如何实现仅接收number类型属性键的泛型函数
限定取对象number类型属性的TS函数实现
目标效果
实现getNumber函数,类型规则如下:
- 传入对象上值为number类型的属性键时,返回值类型为number(支持字面量值精准推导)
- 传入对象上值非number类型的属性键时,直接触发TS编译报错
预期代码表现:
const a = getNumber({a: 3, b: "three"}, "a"); // 编译通过,a类型为number(或字面量类型3) const b = getNumber({a: 3, b: "three"}, "b"); // 编译不通过
原有实现的缺陷
之前的实现通过映射类型把非number属性的值类型标记为never,只能做到传入非number键时返回值为never类型,无法直接拦截这类非法键的传入,且泛型场景下TS无法正确识别t[k]为number类型:
type NumberOnly<T> = { [k in keyof T]: T[k] extends number ? number : never; } const getNumber = <T extends Record<string, any>, K extends keyof NumberOnly<T>>(t: T, k: K):NumberOnly<T>[K] => t[k];
可直接使用的实现
注意:该实现依赖TypeScript 4.1及以上版本支持的键重映射(as 子句)语法,低版本TS无法使用
核心是用键重映射语法,直接过滤出对象中所有值为number类型的键,把泛型K约束为这类合法键的联合类型,从入参阶段就拦截非法键:
// 提取对象T中所有值为number类型的键 type NumberKeys<T> = keyof { [K in keyof T as T[K] extends number ? K : never]: T[K] }; const getNumber = <T extends Record<string, unknown>, K extends NumberKeys<T>>( obj: T, key: K ): T[K] => obj[key];
效果说明
- 传入合法number属性键时,返回值会自动推导为对应属性的类型,默认支持数值字面量精准推导,比如传入
{a:3, b:"three"}取a,返回类型就是字面量3 - 传入非number属性键时,TS会直接报类型错误,提示该键不属于合法的number类型属性键范围
- 泛型场景下可以正确识别返回值为number类型,不会出现类型不兼容的问题
如果不需要字面量精准推导,只需要返回值统一为number类型,调整NumberKeys的映射值即可:
type NumberKeys<T> = keyof { [K in keyof T as T[K] extends number ? K : never]: number };
内容的提问来源于stack exchange,提问作者Michael Lorton
相关产品推荐
相关产品推荐

