TypeScript泛型布尔属性访问器类型不兼容问题求助
问题描述
我尝试编写类型安全的泛型函数,用于获取对象的布尔属性值,却遇到编译器报错,提示T[K]无法赋值给boolean类型。希望尽可能避免使用obj[propName] as unknown as boolean这类类型断言。
基础代码示例
type KeyOfType<T, V> = keyof { [P in keyof T as T[P] extends V ? P : never]: any } function getBooleanValue<T, K extends KeyOfType<T, boolean>>(obj: T, propName: K): boolean { return obj[propName] // ^ // Type 'T[K]' is not assignable to type 'boolean'. // Type 'T[keyof { [P in keyof T as T[P] extends boolean ? P : never]: any; }]' is not assignable to type 'boolean'. // Type 'T[string] | T[number] | T[symbol]' is not assignable to type 'boolean'. // Type 'T[string]' is not assignable to type 'boolean'.(2322) }
实际应用场景(泛型比较器)
type KeyOfType<T, V> = keyof { [P in keyof T as T[P] extends V ? P : never]: any } export function compareByBooleanProperty<T, K extends KeyOfType<T, boolean>>( propName: K, ): (a: T, b: T) => number { const propertyAccessor = (obj: T) => obj[propName] const booleanComparator = compareBooleans return (a: T, b: T) => { const aValue = propertyAccessor(a) const bValue = propertyAccessor(b) return booleanComparator(aValue, bValue) // ^ // Type 'T[K]' is not assignable to type 'boolean'. // Type 'T[keyof { [P in keyof T as T[P] extends boolean ? P : never]: any; }]' is not assignable to type 'boolean'. // Type 'T[string] | T[number] | T[symbol]' is not assignable to type 'boolean'. // Type 'T[string]' is not assignable to type 'boolean'.(2322) } } function compareBooleans(a: boolean, b: boolean): number { // 自定义比较逻辑 return 0 } type Person = { name: string isMarried: boolean } compareByBooleanProperty<Person, "isMarried">("isMarried") // 生成按isMarried属性排序的比较器
解决方案
问题根源
你定义的KeyOfType虽然能筛选出值类型匹配V的键,但TypeScript无法反向推导T[K]必然等于V——因为keyof { ... }最终会被解析为string | number | symbol的子集,TypeScript无法将这个子集与T的属性类型做精准关联。
修正后的代码实现
我们需要调整KeyOfType的定义方式,让它直接约束K对应的属性类型必须是V,同时让TypeScript能明确推导T[K]的类型:
// 重新定义KeyOfType,通过映射取值明确约束属性类型 type KeyOfType<T, V> = { [P in keyof T]: T[P] extends V ? P : never }[keyof T] // 修复后的getBooleanValue函数 function getBooleanValue<T, K extends KeyOfType<T, boolean>>(obj: T, propName: K): boolean { return obj[propName] // 编译器可正确识别T[K]为boolean类型 } // 修复后的泛型比较器函数 export function compareByBooleanProperty<T, K extends KeyOfType<T, boolean>>( propName: K, ): (a: T, b: T) => number { const propertyAccessor = (obj: T) => obj[propName] const booleanComparator = compareBooleans return (a: T, b: T) => { const aValue = propertyAccessor(a) const bValue = propertyAccessor(b) return booleanComparator(aValue, bValue) // 无类型报错 } } function compareBooleans(a: boolean, b: boolean): number { return a === b ? 0 : a ? 1 : -1 // 示例比较逻辑:true排在false后面 } type Person = { name: string isMarried: boolean } // 使用示例:无需手动指定泛型参数,TypeScript会自动推导 compareByBooleanProperty("isMarried")
原理说明
新的KeyOfType通过映射类型取值的方式:先为每个键P生成对应的类型(匹配V则保留P,否则为never),再通过[keyof T]取出所有非never的键。这种方式让TypeScript能明确知道:当K extends KeyOfType<T, V>时,T[K]必然是V的子类型,从而彻底解决类型不匹配的问题。
内容的提问来源于stack exchange,提问作者Nainpo
相关产品推荐
相关产品推荐

