You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何固定类型可赋值给带索引签名的类型,而接口却不行?

TypeScript中type与interface在索引签名类型赋值上的差异

在TypeScript里会遇到一个奇怪的现象:用type定义的固定结构类型可以赋值给带有索引签名的类型,但用interface定义的接口却不行。示例代码如下:

interface JsonObject {
    [key: string]: JsonValue
}
type JsonValue = JsonObject | JsonValue[] | boolean | number | string | null;
export type Json = JsonObject | JsonValue;

//---------------------------------------------------------------

interface A {
    b: string
}
type B = {
    b: string
};

const AValue: A = {
    b: "foo"
};
const BValue: B = {
    b: "foo"
};

function serialize(val: Json) {
    JSON.stringify(val);
}

serialize(AValue); //TS2345错误
serialize(BValue); //无错误

// 以下两行均会报错
AValue["x"] = 4;
BValue["x"] = 4;

核心原因:兼容性检查逻辑的差异

  • type定义的对象类型:结构兼容优先
    TypeScript对type定义的对象类型采用宽松的结构类型检查:只要目标类型(如JsonObject)的索引签名要求,能覆盖源类型(B)的所有已知属性类型,就判定两者兼容。
    示例中JsonObject要求所有字符串键的属性都属于JsonValue类型,而type B的b属性是string,正好是JsonValue的子集,所以B的实例可以被当作JsonObject传入serialize函数。

  • interface定义的类型:精确结构默认不兼容索引签名
    对于interface,TypeScript默认将其视为精确的结构声明——它认为接口A只包含b这一个属性,没有声明索引签名,因此不会自动推断它符合JsonObject的约束。如果想让A兼容JsonObject,需要给接口显式添加对应的索引签名:

    interface A {
      b: string;
      [key: string]: JsonValue;
    }
    

    修改后,AValue就能正常传入serialize函数了。

关于无法添加额外属性的说明

不管是interface A还是type B,它们都没有声明索引签名,所以编译时TypeScript会阻止添加未定义的属性(比如x),这是两者一致的行为,和前面的赋值兼容性问题是独立的逻辑。

内容的提问来源于stack exchange,提问作者Chris

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 23:54:28