为何TypeScript对interface报错却不对type报错?
TypeScript中Interface与Type的索引签名兼容性差异问题
同样定义了结构完全一致的FooInterface接口和FooType类型别名,将它们的实例传入要求带有字符串索引签名的函数fn时,FooInterface的实例会抛出类型不兼容错误,而FooType的实例却能正常运行。
代码示例
const fn = (a: { [key: string]: number | string }) => { console.log(a) }; interface FooInterface { id: number; name: string; } type FooType = { id: number; name: string; } const fooInterface: FooInterface = { id: 1, name: 'name' }; const fooType: FooType = { id: 1, name: 'name' }; fn(fooType); fn(fooInterface); // <-- 此处报错
错误信息
Argument of type 'FooInterface' is not assignable to parameter of type '{ [key: string]: string | number; }'.
Index signature for type 'string' is missing in type 'FooInterface'.
原因分析
类型系统的隐式索引签名规则
函数fn的参数要求是带有string类型索引签名的对象,即所有字符串键对应的属性值必须是number | string类型。
Type别名的特性
FooType是对象字面量的类型别名,TypeScript会隐式判定它符合索引签名要求:
- 它的所有已知属性类型都匹配
number | string; - 类型别名是不可扩展的,不会有后续添加不符合索引签名属性的可能,因此TypeScript允许它赋值给带索引签名的类型。
Interface的特性
FooInterface是接口,TypeScript的接口支持声明合并——你可以在代码的其他位置再次扩展这个接口(比如添加age: boolean这样不符合索引签名的属性)。由于无法保证未来不会出现不符合索引签名的属性,TypeScript不会为接口隐式添加索引签名,因此直接传入时会触发类型不兼容错误。
解决方法
- 给接口显式添加索引签名:
interface FooInterface { [key: string]: number | string; id: number; name: string; } - 使用类型断言:
fn(fooInterface as { [key: string]: number | string }); - 将接口转为类型别名:如果不需要接口的扩展特性,可以直接使用
type替代interface。
内容的提问来源于stack exchange,提问作者Duannx
相关产品推荐
相关产品推荐

