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

为何TypeScript允许将子类型赋值给对象属性?示例报错解析

为何TypeScript允许将子类型赋值给对象属性?

先看你提供的示例代码:

type Base = {
    a: number,
    b: number
}

type SubTest = Base & {
    c: number
}

function run(arg: { prop: Base }) {
    arg.prop = {
        a: 1,
        b: 2
    };
}

const prop: SubTest = {
    a: 1,
    b: 2,
    c: 3
};

const originalObject = { prop };

run(originalObject);

console.log(originalObject.prop.c.toFixed(2));

编译时TypeScript没有报错,但运行时会抛出错误:

originalObject.prop.c is undefined

原因解析

TypeScript采用结构类型系统,判断类型兼容性时只看结构是否匹配。这里SubTest是Base的子类型(包含Base的所有属性,还多了c),所以{ prop: SubTest }可以赋值给{ prop: Base }——这是因为TypeScript默认允许对象属性的协变:子类型属性可以赋值给父类型属性。

但问题出在run函数内部:它直接将arg.prop替换成了一个仅包含a和b的纯Base对象,覆盖了原本的SubTest类型值。此时originalObject.prop的实际值已经丢失了c属性,运行时访问自然会报错。TypeScript没有检测到这个问题,是因为它认为{ prop: Base }类型的参数允许将prop赋值为任何Base类型的实例,包括不包含额外属性的版本。

解决方法

可以通过以下几种方式避免这类运行时错误:

  1. 将属性设为只读
    修改run函数的参数类型,把prop标记为只读,禁止内部修改:

    function run(arg: { readonly prop: Base }) {
        // 这里会报错:无法分配到 "prop" ,因为它是只读属性。
        arg.prop = { a: 1, b: 2 };
    }
    
  2. 使用泛型约束
    让函数接受泛型参数,确保赋值的类型与原始子类型一致:

    function run<T extends Base>(arg: { prop: T }) {
        // 这里只能赋值为 T 类型的对象,不能用纯 Base
        arg.prop = { a: 1, b: 2, c: 3 } as T;
    }
    
  3. 约束原始对象的属性为只读
    定义originalObject时把prop设为只读,避免外部函数修改:

    const originalObject: { readonly prop: SubTest } = { prop };
    // 传递给 run 时会报错,因为 run 接受的是可写的 prop 属性
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 00:53:26