使用品牌类型键与对象展开时TypeScript未检测类型错误
TypeScript品牌化字符串作为对象键时,对象展开导致类型检查失效的问题
这是TypeScript的已知编译器bug,既不是你的理解错误,也不属于预期行为。
问题复现
你的最小复现代码已经准确命中了这个bug场景:
type SpecialKey = string & {__SpecialKey: true}; type SpecialKeysToStrings = { [key: SpecialKey]: string; } // 正常工作 const obj1: SpecialKeysToStrings = { ['myKey' as SpecialKey]: "string", }; // 值非string,编译器正确捕获错误 const obj2: SpecialKeysToStrings = { ['myKey' as SpecialKey]: 100, }; // 值非string,编译器未检测到错误(bug触发点) const obj3: SpecialKeysToStrings = { ...{}, ['myKey' as SpecialKey]: 100, }
原因分析
品牌化字符串是TypeScript中模拟名义类型的常用手段,但TypeScript的对象字面量类型合并逻辑在处理「展开语法 + 品牌化键」的组合时存在漏洞:
- 当对象字面量中存在展开操作时,编译器会先处理展开的对象类型,再合并后续属性
- 此时品牌化键的特殊约束会被降级为普通
string类型,导致后续属性的值类型检查完全绕过了SpecialKeysToStrings中string值的要求
临时解决方案
可以通过以下方式规避这个bug:
- 直接创建不含展开语法的对象字面量(如obj1、obj2的写法)
- 使用
Object.assign替代展开语法,保留类型检查:const obj3: SpecialKeysToStrings = Object.assign({}, { ['myKey' as SpecialKey]: 100 // 这里会正确触发类型错误 });
内容的提问来源于stack exchange,提问作者joshuahhh
相关产品推荐
相关产品推荐

