TypeScript返回不可变/常量/只读数组

35

我想要一个返回数组的方法,但希望返回的数组为只读,这样当我尝试修改其内容时就会收到警告/错误提示。

function getList(): readonly number[] {
   return [1,2,3];
}


const list = getList();
list[2] = 5; // This should result in a compile error, the returned list should never be changed

这个能在 TypeScript 中实现吗?


使用 Readonly<number[]> 存在一个问题。我不能再使用 for...of,因为类型必须具有返回迭代器的方法。 - XCS
...而且它似乎不起作用。这里应该会出现错误,对吧? - T.J. Crowder
我不认为这是一个完全的重复。从我所看到的来看,被接受的答案甚至在其他问题中都不起作用。 - Matthew Layton
1
@series0ne:是的,就像上面说的一样。我去尝试了一下,这样我就可以评论一个例子(我喜欢在重复的情况下这样做),但是...它没有起作用。 :-) - T.J. Crowder
在纯JS中,您可以使用a => Object.freeze(a);a数组转换为浅不可变。尝试更改或删除其项似乎会在严格模式下抛出“类型错误”,但在其他情况下则会默默失败。如果其中任何一个项目是引用类型,则除非您递归地冻结它们,否则它将保持可变。 - Redu
6个回答

36

这似乎有效...

function getList(): ReadonlyArray<number> {
    return [1, 2, 3];
}

const list = getList();

list[0] = 3; // Index signature in type 'ReadonlyArray<number>' only permits reading.

尝试在Playground中测试一下。 ReadonlyArray<T>是这样实现的:
interface ReadonlyArray<T> {
    readonly [n: number]: T;
    // Rest of the interface removed for brevity.
}

谢谢,这正是我在寻找的。我认为TypeScript文档在这方面缺乏,没有太多关于这个功能的参考。 - XCS

32

现在从原始问题中的代码已经能够正常工作,因为自 TypeScript 3.4 开始,引入了一个新的语法用于 ReadonlyArray:

  

尽管在没有意图进行变异时使用 ReadonlyArray 而不是 Array 是一个好习惯,但往往会遇到困难,因为数组具有更简洁的语法。特别是,number[]Array<number> 的简写版本,而 Date[] 则是 Array<Date> 的简写。

     

TypeScript 3.4 引入了一个新的语法,使用新的 readonly 修饰符来定义只读数组类型。

此代码现在按预期工作:

function getList(): readonly number[] {
   return [1,2,3];
}

const list = getList();
list[2] = 5; // <-- error

游乐场


5
以下代码将使列表只读,但其中的项目不受影响:
function getList(): Readonly<number[]> {
   return [1,2,3];
}

let list = getList();
list = 10; // error
list[1] = 5 // that is fine

这个代码片段会使得列表和其中的项都只读:

function getList(): ReadonlyArray<number> {
   return [1,2,3];
}

let list = getList();
list = 10; // error
list[1] = 5 // error as well

1

TypeScript拥有ReadonlyArray<T>类型,它可以做到这一点:

TypeScript带有一个ReadonlyArray类型,与Array相同,但删除了所有变异方法,因此您可以确保在创建后不更改数组。

function getList(): ReadonlyArray<number> {
   return [1,2,3];
}

const list = getList();
list[2] = 5; // error

for (const n of list) {
    console.log(n);
}

0

您可以使用Object.freeze来返回一个只读数组,而不需要使用任何类型注释:

function getList() {
  return Object.freeze([1,2,3]);
}

const list = getList();
list[2] = 5; // error

console.log(list);

0

另一种选择是 as const 关键字。

"as const 声明变量或常量的内容为只读,并确保变量或常量的内容不被更改" (src)

function getList() {
  return [1,2,3] as const
}

const list = getList();
list[2] = 5; // error

错误:无法对 '2' 进行赋值,因为它是只读属性。
您的 IDE 将显示的结果是什么:
function getList(): readonly [1, 2, 3]

优点:是否干净(无需手动定义返回类型或创建新类型)

缺点:不明确


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接