TypeScript中特定对象类型为何无法赋值给Record类型的TableRow?
报错原因
Record<string, string | number | undefined> 本质是声明了带字符串索引签名的类型,含义是「该类型可以用任意字符串作为键访问,对应的值符合指定类型要求」。
而通过 interface 声明的业务类型默认没有隐式的字符串索引签名,就算它的所有属性值都符合Row的值要求,TypeScript 也不会默认认为它和带索引签名的类型兼容,因此触发报错。
补充说明:如果你直接向Row类型的变量赋值对象字面量 const row: Row = {name: 'Jim'} 不会报错,这是因为TypeScript对新鲜的对象字面量会做隐式适配,允许赋值给带索引签名的类型,而已被声明为具体interface类型的变量不会触发该适配。
解决方案
我们可以根据使用场景选择以下两种通用方案,都能满足「强制约束行对象所有属性值都是原始类型」的要求:
方案1:使用泛型约束适配任意业务类型(推荐)
如果需要接收任意符合值要求的对象,不需要业务类型额外做改造,用泛型做校验即可:
// 先定义行属性允许的原始类型范围,可根据需求调整 type RowPrimitive = string | number | boolean | null | undefined // 用于校验行类型的泛型工具 type ValidRow<T> = { [K in keyof T]: RowPrimitive } // 业务类型不需要做任何改造 interface User { name: string } const jim: User = { name: 'Jim' } // 赋值时做类型校验,不符合值要求会直接报错 const row: ValidRow<User> = jim
如果是在函数参数中使用,可以直接写泛型约束更简洁:
function processRow<T extends Record<string, RowPrimitive>>(row: T) { // 内部处理逻辑 } // 直接传符合要求的对象即可,自动校验 processRow(jim)
方案2:给业务interface添加索引签名
如果你确定要保留Row为Record的写法,可以给业务interface显式添加字符串索引签名:
export type Row = Record<string, string | number | undefined> interface User { name: string // 显式声明索引签名,和Row的要求对齐 [key: string]: string | number | undefined } const jim: User = { name: 'Jim' } const row: Row = jim // 不会再报错
该方案的缺点是每个要作为行使用的业务类型都需要单独加索引签名,灵活性低于泛型方案。
内容的提问来源于stack exchange,提问作者Alex Craft
相关产品推荐
相关产品推荐

