TypeScript中type与interface定义类型传参为何出现报错差异?
TypeScript中type与interface泛型类型赋值差异的原因
问题重现
编写TypeScript代码时遇到以下差异:
type Arg = Record<PropertyKey, unknown> function foo(d: Arg) { console.log(d) } type M<T, D> = { type: T, data: D } type MyType1 = M<'bar', {name: string}> const a1: MyType1 = {type: 'bar', data: {name: 'xxx'}} foo(a1) // 正常通过 interface N<T, D> { data: D type: T } type MyType2 = N<'xyz', {name: number}> const a2: MyType2 = {type: 'xyz', data: {name: 2}} foo(a2) // 报错:Argument of type 'MyType2' is not assignable to parameter of type 'Arg'. Index signature for type 'string' is missing in type 'N<"xyz", { name: number; }>'.
原因分析
核心差异来自TypeScript对type别名和interface的类型兼容性处理逻辑:
type别名的对象类型是“封闭”的:type M<T,D>定义的是匿名对象类型的别名,实例化后的MyType1是固定结构的对象类型,TypeScript认为它的所有属性都已明确声明,没有后续扩展的可能。因此赋值给Record<PropertyKey, unknown>(带有任意属性的索引签名类型)时,会被允许兼容。interface是“开放”的:interface N<T,D>属于接口类型,TypeScript支持接口的声明合并——即使当前只定义了type和data两个属性,后续仍可通过额外的interface N声明添加新属性。因此TypeScript无法确定该接口类型是否满足“拥有任意属性的索引签名”要求,所以拒绝赋值。
解决方法
如果需要让interface定义的类型能赋值给Arg,可以显式添加匹配的索引签名:
interface N<T, D> { data: D type: T // 添加索引签名,对齐Arg的类型要求 [key: PropertyKey]: unknown }
添加后,a2就能正常传入foo函数。
内容的提问来源于stack exchange,提问作者Lynch
相关产品推荐
相关产品推荐

