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

TypeScript接口中getter与readonly属性的区别是什么?

TypeScript中readonly属性接口与getter接口的差异

先看这两个TypeScript接口定义:

interface A {
    readonly x: number;
}

interface B {
    get x(): number;
}

有人发现,实现这两个接口时,方式可以互换:用getter实现接口A,或者用readonly属性实现接口B,代码示例如下:

class ClassA implements A {
    // x = 1; <- 这样写也能实现A
    get x() {
        return 1;
    }
}

class ClassB implements B {
    // get x() { <- 这样写也能实现B
    //     return 1;
    // }
    x = 1;
}

那这两个接口之间到底有没有差异?答案是有明显差异,具体体现在以下几个方面:


1. 字面量赋值的限制不同

  • 对于接口A,可以直接给变量赋值普通字面量,因为readonly x只是编译时的只读约束,允许初始化赋值:
    const a: A = { x: 1 }; // 完全合法
    
  • 对于接口B,不能直接赋值普通字面量,因为接口要求的是get x()访问器,普通字面量的属性不符合这个要求:
    const b: B = { x: 1 }; // 编译报错:类型"{ x: number; }"无法赋值给类型"B"
    // 正确写法必须带getter:
    const b: B = { get x() { return 1; } };
    

2. 运行时行为的本质区别

  • 接口A的readonly x是编译时约束,编译后的JS代码中,这个属性和普通属性没有区别,只要绕开TypeScript的类型检查,运行时可以修改:
    const a: A = { x: 1 };
    (a as any).x = 2; // 运行时能成功修改,不会报错
    
  • 接口B的get x()是真正的访问器,编译后的JS代码里会生成getter函数,运行时尝试赋值会被忽略(严格模式下直接报错):
    const b: B = { get x() { return 1; } };
    (b as any).x = 2; // 非严格模式下无报错,但x的值还是1;严格模式下抛错
    

3. 接口扩展/合并的规则不同

  • 扩展readonly接口时,无法将readonly属性改为可写:
    interface ExtendA extends A {
        x: number; // 编译报错:无法将只读属性"x"修改为可写
    }
    
  • 扩展getter接口时,可以添加对应的setter,把只读访问器改成可读可写:
    interface ExtendB extends B {
        set x(value: number); // 完全合法,此时ExtendB的x是可读可写的
    }
    

4. 类型兼容性的细微差异

虽然类实现时可以互换方式,但在某些场景下,两个接口的类型兼容性并不完全对称:

  • 带有readonly属性的类型可以赋值给getter接口类型:
    const a: A = { x: 1 };
    const b: B = a; // 合法
    
  • 但反过来,如果getter接口的实现是动态计算值的对象,赋值给readonly接口类型虽然合法,但运行时行为不同(每次访问x都会调用getter),这可能和预期的readonly属性行为(一次赋值后不变)有差异。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 15:22:29