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

TypeScript类属性中readonly与const断言的区别是什么

TypeScript类属性上readonly修饰符与as const断言的核心差异

你在42这个单数字字面量的极简示例里觉得二者效果一致,本质是特殊场景下的巧合——这两个语法根本作用在完全不同的维度,互不冲突,所以既可以单独使用也可以组合使用。

核心作用逻辑完全不同

  • readonly是属性级的类型修饰符,唯一作用是在类型检查阶段禁止给该属性重新赋值,它不会改变属性值本身的类型推导结果。
  • as const是值级的类型断言,唯一作用是把紧跟在它前面的那个值的类型推导收窄到最精确的字面量类型,它完全不关心所属的属性能不能被重新赋值。

你可以用几行代码直接戳破42示例下的"效果一致"错觉:

// 仅用as const
class Test1 {
  ANSWER = 42 as const;
}
const t1 = new Test1();
t1.ANSWER = 42; // 完全不报错,as const根本不阻止属性赋值,只要值符合字面量42的类型就可以
t1.ANSWER = 43; // 报错:类型不匹配,不是因为不能赋值,是43不符合字面量类型42

// 仅用readonly
class Test2 {
  readonly ANSWER = 42;
}
const t2 = new Test2();
t2.ANSWER = 42; // 直接报错:readonly修饰的属性不允许重新赋值,哪怕赋的值和原来完全一样

对引用类型的约束差异更明显

拿数组举例子,二者负责的范围完全不重叠:

// 仅用readonly
class A {
  readonly arr = [1, 2];
}
const a = new A();
a.arr = [3,4]; // 报错:readonly禁止给属性重新赋新的引用
a.arr.push(3); // 不报错:readonly不会收窄数组类型,arr的常规推导类型是number[],允许修改内部元素

// 仅用as const
class B {
  arr = [1,2] as const;
}
const b = new B();
b.arr = [1,2]; // 不报错:属性没有readonly修饰,只要赋的值符合只读元组[1,2]的类型就可以
b.arr.push(3); // 报错:as const把数组推导成只读元组,禁止修改内部元素

简单总结二者的约束边界:

  • readonly管「属性的引用能不能换」,不管引用指向的值本身能不能改
  • as const管「值本身的类型够不够精确、值内部能不能改」,不管属性的引用能不能换

为什么允许组合使用

因为二者管的事情完全不重叠,组合使用才能实现真正意义上的常量属性:既不允许给属性重新赋值,也把值的类型收窄到最精确的字面量,同时禁止修改值内部的元素/属性。

class Test {
  readonly ANSWER = 42 as const;
  readonly arr = [1,2] as const;
}
const t = new Test();
t.ANSWER = 42; // 报错:禁止重赋值
t.arr = [1,2]; // 报错:禁止重赋值
t.arr.push(3); // 报错:禁止修改内部元素

各自适用场景

  • 单独用readonly:适合只需要禁止属性重赋值,不需要收窄字面量类型的场景,比如属性值是构造函数传入、运行时计算、接口返回的非固定值——这类场景下as const没有意义,因为值本身不是静态字面量,没法收窄类型。缺点是无法约束引用类型值的内部修改。
  • 单独用as const:类属性场景下几乎不会单独使用,毕竟如果允许属性随便重赋值,收窄初始值类型的意义不大,仅在极少数需要强制所有赋值都匹配初始字面量类型的特殊场景下才会单独用。
  • 组合使用:适合定义类里的静态常量,是最严谨的写法。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.01 21:57:36