为什么打字稿允许通过可变类型引用/分配只读类型/属性?

Bas*_*adi 1 readonly typescript

为什么打字稿不强制 readonly 关键字并阻止我们将只读属性传递给非只读属性,这违背了这一点

let foo: {
    readonly bar: number;
} = {
        bar: 123
    };

function iMutateFoo(foo: { bar: number }) {
    foo.bar = 456;
}

iMutateFoo(foo); // The foo argument is aliased by the foo parameter
console.log(foo.bar); // 456!```
Run Code Online (Sandbox Code Playgroud)

jca*_*alz 5

这是一种已知的行为,在microsoft/TypeScript#13347上进行了跟踪,其令人惊讶的效果激发了最初标题为“只读修饰符是个笑话”的问题。readonly这个问题的简短回答是“它在引入时会破坏​​向后兼容性”。长答案来自以下评论:

@ahelsberg

为了确保向后兼容性,readonly修饰符不会影响包含类型的子类型和可赋值类型关系(但当然它会影响对各个属性的赋值)。

考虑以下代码:

interface ArrayLike<T> {
  length: number;
  [index: number]: T;
}

function foo(array: ArrayLike<string>) {
   // Doesn't mutate array
}

var s = "hello";
var a = ["one", "two", "three"];
foo(s);  // s has readonly length and index signature
foo(a);
Run Code Online (Sandbox Code Playgroud)

在现有的 TypeScript 代码中,无法指示特定属性是只读还是可变。在上面的代码中,foo不会改变它传递的数组,但代码中没有任何内容表明它不能。然而,现在我们已经在接口中readonlylength属性和索引签名添加了修饰符String(因为它们实际上是只读的),foo(s)如果我们说某个readonly属性与没有readonly. 具体来说,我们不能将没有readonly修饰符解释为读写,只能说我们不知道。因此,如果一个接口与另一个接口仅在readonly其属性的修饰符上有所不同,我们就必须说这两个接口是兼容的。其他任何事情都将是一个巨大的突破性改变。

所以你有它。如果您想表达对解决此问题的支持,您可能需要转到该GitHub 问题并给出一个或描述您的用例(如果它引人注目且尚未提及)。