TypeScript 如何约束泛函数参数为对应值为number的泛型键
mkSorter函数的数值属性类型约束实现
基础工具类型定义
首先需要定义一个工具类型,从任意对象类型T中提取所有值类型为number的键名,组合成联合类型:
type NumericKeys<T> = { [P in keyof T]: T[P] extends number ? P : never }[keyof T]
该工具类型的遍历逻辑:逐个判断
T的键对应的值类型是否为number,匹配则保留当前键名,不匹配则返回never,最后合并所有有效键名形成联合类型。针对示例中的SomeObjectType,该工具类型会直接得到'number' | 'alsoNumber'的联合类型。
如果使用TS 4.1及以上版本,可以用键重映射的语法写出可读性更强的等价实现:
type NumericKeys<T> = keyof { [P in keyof T as T[P] extends number ? P : never]: T[P] }
完整函数实现
将原函数中泛型K的约束从keyof T替换为上述NumericKeys<T>,即可实现对传入属性的类型限制,完整代码如下:
function mkSorter< T extends { [key: string]: unknown }, K extends NumericKeys<T> >(prop: K) { // 因K已被约束为T中值为number的键,a[prop]的类型天然为number,减法运算不会触发类型报错 return (a: T, b: T) => a[prop] - b[prop]; }
实现效果
- 严格类型校验:调用函数时仅可传入目标类型
T中值为number的属性名,传入字符串、布尔值等非数值类型的属性时,会直接收到TypeScript的类型错误提示 - 正常支持自动补全:由于
K的约束直接与T的数值键做绑定,TypeScript在类型提示阶段可直接枚举所有合法的属性名,输入时会自动弹出可选的键名列表 - 完全匹配使用场景:示例中
mkSorter<SomeObjectType>('alsoNumber')的调用方式可正常通过类型校验,与表格组件的ColumnsType的sorter字段类型兼容
旧方案自动补全失效的原因
之前提供的绕层交叉类型的方案,之所以无法正常触发自动补全,是因为方案额外引入了NumericFields<T>的交叉类型泛型N,拉长了TypeScript对prop参数合法值的推断链路:TS无法直接从泛型T的定义一步定位到所有合法的prop候选项,需要额外推导交叉类型的键集合,这个推导过程会丢失自动补全所需的枚举信息,导致提示失效。
内容的提问来源于stack exchange,提问作者vyenkv
相关产品推荐
相关产品推荐

