TypeScript中如何为Record的key正确标注类型以解决类型错误
问题:为filterProps函数的key标注类型解决类型错误
我编写了一个根据过滤函数筛选对象属性的filterProps函数,代码如下:
function filterProps<K extends string, V>(object: Record<K, V>, fn: (key:K, value: V, object: Record<K, V>) => unknown) { // return a new object with only the properties filtered by fn return Object.entries(object).reduce( (acum, [key, value]) => fn(key, value, object) ? {...acum, [key]: value } : acum, {} as Record<K, V> ) }
运行时出现如下类型错误:
(parameter) key: string
Argument of type 'string' is not assignable to parameter of type 'K'.
'string' is assignable to the constraint of type 'K', but 'K' could be instantiated with a different subtype of constraint 'string | number | symbol'.(2345)
请问该如何为key标注类型以避免这个错误?
解决方案
问题根源在于Object.entries()返回的键类型固定为string,但泛型K是string的子类型(比如具体字面量类型),TypeScript无法自动推导二者等价。下面提供两种可行解决方式:
方式一:类型断言快速修复
直接将key断言为K类型,同时显式确认value的V类型:
function filterProps<K extends string, V>(object: Record<K, V>, fn: (key:K, value: V, object: Record<K, V>) => unknown) { return Object.entries(object).reduce( (acum, [key, value]) => fn(key as K, value as V, object) ? {...acum, [key]: value } : acum, {} as Record<K, V> ) }
方式二:类型守卫增强安全性
如果不想使用直接断言,可添加类型守卫函数在运行时验证key属于K,同时让TypeScript在编译时确认类型:
// 类型守卫:确认key是目标对象的键类型 function isKeyOf<K extends string>(key: string, obj: Record<K, unknown>): key is K { return key in obj; } function filterProps<K extends string, V>(object: Record<K, V>, fn: (key:K, value: V, object: Record<K, V>) => unknown) { return Object.entries(object).reduce( (acum, [key, value]) => { // 先验证key类型,再执行过滤逻辑 if (isKeyOf(key, object) && fn(key, value, object)) { return {...acum, [key]: value }; } return acum; }, {} as Record<K, V> ) }
补充说明
Object.entries()的类型设计是为了兼容所有对象,JavaScript中对象的键最终都会转为字符串,因此TypeScript默认返回string类型的键。- 对于泛型
K为字面量类型的场景(比如'name' | 'age'),类型断言或守卫能让TypeScript确认当前遍历的键就是K的成员,消除类型不匹配错误。
内容的提问来源于stack exchange,提问作者opensas
相关产品推荐
相关产品推荐

