我有一些本不想执行的 TypeScript 代码,但它却执行了,为什么?
let a:[boolean, ... readonly string[]] = [true, '1', '2', '3'];
a[0] = false;
a[1] = 'one'; //no error, but it should be error
您的代码没有产生错误的原因是,尽管您有注释,
a
的类型会立即被编译器减少为完全可变类型[boolean, ...string[]]
:
let a: [boolean, ... readonly string[]] = [true, '1', '2', '3'];
type A = typeof a;
// type A = [boolean, ...string[]]
因此
a
的所有元素都不是只读的。这就是所问问题的答案。
明显的后续问题是“为什么它会被简化为完全可变的类型?”。不幸的是,我找不到任何权威来源,所以我在这里所说的一切都只是猜测。来了:
类型
[T, ...A]
是将 A
类型的数组 spread到以
t
类型的值开头的数组文字的末尾时获得的类型。以下函数编译没有错误的事实证明了这一点:
function f<T, A extends readonly any[]>(t: T, a: A): [T, ...A] {
return [t, ...a]
}
如果我有一个只读字符串数组并将其传播到数组文字的末尾,则生成的数组将不是只读的:
const strs: readonly string[] = ["x", "y"]
const result = f(true, strs);
// const result: [boolean, ...string[]]
这就是我的猜测。如果有人找到任何证实或反驳这一点的规范来源(例如 TS 文档或 GitHub 问题),我很有兴趣了解它。
它之所以有效,是因为
readonly
只是各个元素本身。数组本身仍然是可变的。
如果你这样做了
let a:readonly [boolean, ... readonly string[]] = [true, '1', '2', '3'];
a[0] = false; // error
a[1] = 'one'; //error
然后,是的,它会出错,因为您已将数组本身标记为只读,而不仅仅是其某些值。
扩展数组/元组只是有序地列出该数组的元素。
它只是从数组中取出值,而不实际修改/传输推断的特征
let xs = [1,2,3,4]
let ys = [...xs] // [1,2,3,4]
因此当我们这样做时
let a:[boolean, ... readonly string[]] = [true, '1', '2', '3'];
我们只是说从
readonly string array
中提取所有值,而不是使这些值成为 readonly
。
这就是行为。