TypeScript中readonly与ReadonlyArray处理数组的差异及选型疑问
TypeScript中readonly修饰符与ReadonlyArray的差异解析
先看示例代码:
class ReadonlyArrsClass { readonly arr: string[] = ['1', '2']; arr2: ReadonlyArray<string> = ['1', '2']; addToArr(): void { this.arr.push('333'); // 正常执行 } addToArr2(): void { this.arr2.push('444'); // 报错:类型'readonly string[]'上不存在属性'push' } changeArrData(): void { this.arr = ['555']; // 报错:无法赋值给'arr',因为它是只读属性 } changeArr2Data(): void { this.arr2 = ['666']; // 正常执行 } logToConsole(): void { console.log(this.arr); console.log(this.arr2); } constructor(){ this.addToArr(); this.addToArr2(); this.logToConsole(); this.changeArrData(); this.changeArr2Data(); this.logToConsole(); } } new ReadonlyArrsClass;
疑问
- 为何用readonly修饰的arr可以通过push()添加元素,而ReadonlyArray类型的arr2却不行?
- 为何ReadonlyArray类型的arr2可以重新赋值引用,而readonly修饰的arr却不能?
差异原因解析
问题1:添加元素的差异
readonly arr: string[]里的readonly是属性修饰符,它只限制属性本身的引用不能被重新赋值,但属性指向的数组对象是普通可变数组(string[]),支持push、pop等修改内部元素的方法,所以可以调用push修改数组内容。arr2: ReadonlyArray<string>里的ReadonlyArray是只读数组类型,它的定义直接屏蔽了所有会修改数组内容的方法(比如push、splice),只保留读取类方法(比如slice、map),所以无法修改数组内部元素。
问题2:重新赋值的差异
readonly修饰的核心作用就是禁止对属性进行引用重新赋值,不管属性指向的是什么类型,都不能用this.arr = 新值的方式改变它的引用。ReadonlyArray<string>只是限定了变量的类型为只读数组,但没有限制变量本身的引用可变性。只要新赋值的内容符合ReadonlyArray<string>类型(比如普通数组可以兼容赋值),就可以给arr2重新赋值。
推荐用法
- 若需要属性引用不可变,但允许修改数组内部元素:使用
readonly arr: string[]。 - 若需要数组内部元素不可修改,但允许属性引用被重新赋值:使用
arr2: ReadonlyArray<string>(或更简洁的readonly string[]语法)。 - 若需要既禁止属性引用重新赋值,又禁止修改数组内部元素:结合两者写成
readonly arr3: ReadonlyArray<string>或readonly arr3: readonly string[]。
这类特性能在编译阶段约束数据的可变性,避免意外修改,提升代码健壮性,在团队协作或复杂项目中建议根据实际需求合理使用。
内容的提问来源于stack exchange,提问作者kassfb
相关产品推荐
相关产品推荐

