TypeScript如何从对象值提取类型并实现函数入参自动推断
问题根因
- 你定义的
arr默认被TypeScript推断为{ type: string }[]类型,type属性的类型被自动拓宽为string而非'a' | 'b'字面量联合类型,导致后续infer提取到的类型也是string,无法限制参数范围。 - 原有泛型定义没有针对字面量推断做优化,也没有兼容
as const生成的只读数组类型。
方案1:加const断言锁死字面量类型
如果数组内容是固定不变的,直接给数组加as const防止类型拓宽,同时调整类型定义兼容只读数组即可:
// as const会把数组锁为只读字面量类型,type属性保持'a'|'b'的联合类型 const arr = [{type:'a'}, {type:'b'}] as const // 调整TypeFromVal适配只读数组 type TypeFromVal<T> = T extends readonly {type: infer R}[] ? R : never // 函数泛型也兼容只读数组 function GetType<T extends readonly {type: string}[]>(arr: T, type: TypeFromVal<T>) { return arr.find(item => item.type === type)!.type } // 调用时会直接报错 GetType(arr, 0) // 类型错误:0不属于 "a" | "b" 联合类型 // 合法调用 GetType(arr, 'a') // 类型校验通过
方案2:调整泛型结构自动推断字面量
如果不想每次都手动加as const,可以拆分泛型参数让TypeScript自动收窄type的类型:
function GetType<T extends string, U extends {type: T}[]>(arr: U, type: T) { return arr.find(item => item.type === type)!.type } // 不需要加as const也能正确推断 const arr = [{type:'a'}, {type:'b'}] GetType(arr, 0) // 直接触发类型错误 GetType(arr, 'a') // 校验正常通过
原理说明
- TypeScript默认定义可变对象/数组时,会把字符串属性的类型拓宽为通用的
string类型,as const可以强制把类型锁为最窄的字面量类型 - 方案2通过先声明单个
type的泛型T,再用T约束数组项的type属性,TypeScript会优先从数组实际值推断T的字面量联合类型,不需要额外做类型断言
内容的提问来源于stack exchange,提问作者user16941843
相关产品推荐
相关产品推荐

