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

ReadonlyArray与readonly arr: T[]的区别及三类接口差异解析

TypeScript中ReadonlyArray与readonly arr: T[]的区别及接口差异解析

先看你提供的代码示例:

interface Feature {
  readonly name: string;
}

// 规则判定OK
interface Foo1 {
  readonly arr: ReadonlyArray<Feature>;
}
function save1(foo: Foo1) {
  console.log(foo);
}

// 规则判定bad
interface Foo2 {
  arr: ReadonlyArray<Feature>;
}
function save2(foo: Foo2) {
  console.log(foo);
}

// 规则判定bad
interface Foo3 {
  readonly arr: Feature[];
}
function save3(foo: Foo3) {
  console.log(foo);
}

你原本以为这三个接口等价,但@typescript-eslint/prefer-readonly-parameter-types规则给出了不同判定,下面拆解它们的差异,以及ReadonlyArray<T>和readonly arr: T[]的核心区别。

三个接口的差异

Foo1:双重只读保障

readonly arr: ReadonlyArray<Feature> 做了两层只读限制:

  • 第一层:属性arr本身是只读的——你不能在函数内部给foo.arr重新赋值(比如foo.arr = []会报错)。
  • 第二层:arr指向的数组内容是只读的——因为ReadonlyArray类型禁用了所有修改数组的方法(push/pop/splice等),也不能通过索引修改元素(比如foo.arr[0] = {name: "new"}会报错)。
    完全符合eslint规则要求的“参数不可被修改”,所以判定为OK。

Foo2:数组内容只读,但属性可写

arr: ReadonlyArray<Feature> 只限制了数组内容不可变,但属性arr本身是可写的——你可以在函数内部给foo.arr重新赋值一个新的数组(比如foo.arr = [{name: "new"}]是合法的)。
eslint规则希望参数的所有属性都保持只读,避免函数内部意外修改参数结构,所以判定为bad。

Foo3:属性只读,但数组内容可写

readonly arr: Feature[] 只限制了属性arr不能被重新赋值,但arr指向的是普通Feature[]数组——你可以在函数内部修改数组内容,比如foo.arr.push({name: "new"})(不过Feature的name是只读,无法修改元素的name,但数组的增删操作是允许的)。
因为数组内容仍可被修改,违反了规则“参数应只读”的核心要求,所以判定为bad。

ReadonlyArray与readonly arr: T[]的核心区别

要分两种场景来看:

  1. 作为独立类型标注时:
    readonly T[] 是ReadonlyArray<T>的语法糖,两者是等价的类型,都表示内容不可变的数组——不能修改元素、不能调用修改类方法。

  2. 作为接口属性的一部分时:

    • arr: ReadonlyArray<T>:重点在数组内容只读,但属性arr本身可以被重新赋值。
    • readonly arr: T[]:重点在属性arr不能被重新赋值,但数组内容是可变的(因为是普通T[]类型)。

简单总结:前者管数组内容不能改,属性能改;后者管属性不能改,数组内容能改。如果要同时锁死两者,就用readonly arr: ReadonlyArray<T>(也就是Foo1的写法)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 10:05:00