为何TypeScript映射类型未报错?排除字段仍可赋值
问题原因分析
核心原因是你定义的JsonType<Test>最终等价于空对象类型{},而TypeScript中的{}并非“完全没有任何属性的对象”,它表示“非null/undefined的任意对象”——只要对象不是null或undefined,无论它带有多少额外属性,都符合{}的类型要求。
具体拆解:
- 你的
Test类型仅包含salt和hash两个键,经过Exclude<keyof T, "salt" | "hash">处理后,得到的是空联合类型,因此映射生成的JsonType<Test>就是没有任何属性的{}类型。 - 在TypeScript的结构类型系统中,
{}类型不限制对象拥有额外属性,所以你给testObject赋值包含salt和hash的对象时,不会触发报错。
解决方法:严格禁止额外属性
如果你的目标是彻底禁止对象包含salt和hash字段,可以修改JsonType的定义,添加索引签名来限制额外属性:
type JsonType<T> = Omit<T, "salt" | "hash"> & { [key: string]: never; }; type Test = { salt: string; hash: string; }; const testObject: JsonType<Test> = { hash: "...", // 触发报错:类型“string”的属性“hash”不能赋给类型“never”的索引签名属性 salt: "...", };
这里的{ [key: string]: never }表示:对象不能有任何字符串类型的额外属性,否则会因为属性值类型(比如string)与索引签名要求的never类型不匹配而报错。
补充说明
如果你的Test类型包含其他属性,比如:
type Test = { salt: string; hash: string; username: string; };
此时JsonType<Test>会是{ username: string },这时候给它赋值包含salt的对象时,TypeScript会触发额外属性检查并报错——只有当目标类型是{}这种无属性定义的空类型时,额外属性才不会被拦截。
内容的提问来源于stack exchange,提问作者Susbakun
相关产品推荐
相关产品推荐

