TypeScript如何在强制对象值类型的同时推断对象字面量类型?
解决方案:用泛型函数实现类型约束与键名推断
要同时满足值类型强制约束和具体键名类型推断,可以通过泛型函数来实现,核心思路是用泛型捕获对象字面量的具体类型,同时约束其值必须符合目标类型。
步骤1:定义目标值类型
type Fruit = 'apple' | 'banana' | 'pear';
步骤2:编写泛型约束函数
创建一个泛型函数,接收对象参数并返回原类型,同时通过extends Record<string, Fruit>约束所有值必须是Fruit类型:
const createFruitMap = <T extends Record<string, Fruit>>(obj: T): T => obj;
步骤3:使用示例
合法场景(值符合Fruit类型)
const myFruits = createFruitMap({ morningSnack: 'apple', afternoonSnack: 'banana', dessert: 'pear' }); // 此时 keyof typeof myFruits 的结果是 'morningSnack' | 'afternoonSnack' | 'dessert' // 完美保留了具体键名的类型推断
非法场景(值不符合Fruit类型)
如果传入非Fruit值,TypeScript会直接抛出编译错误:
const invalidFruits = createFruitMap({ breakfast: 'orange' // 报错:类型'"orange"'不能赋值给类型'Fruit' });
为什么这个方案可行?
- 泛型
T会自动推断为传入对象字面量的具体类型,因此能保留所有键名的精确类型。 T extends Record<string, Fruit>确保了T的每一个值都必须属于Fruit类型,实现了值的强制约束。
对比你之前的写法问题
- 无类型注解的写法:缺少值类型约束,TypeScript不会检查值是否符合
Fruit,因此非法值不会报错。 {[k in string]: Fruit}注解的写法:因为直接指定了宽泛的索引类型,TypeScript会放弃对具体键名的推断,将keyof结果转为string,丢失了键的精确类型信息。
内容的提问来源于stack exchange,提问作者JD Isaacks
相关产品推荐
相关产品推荐

