【问题标题】:Why typescript allows referencing/assigning a readonly type/property by mutable type?为什么打字稿允许通过可变类型引用/分配只读类型/属性?
【发布时间】:2019-07-23 14:26:45
【问题描述】:

为什么 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!```

【问题讨论】:

标签: typescript readonly


【解决方案1】:

这是一个known behavior,其惊人的效果激发了最初标题为"readonly modifiers are a joke" 的问题。对这个问题的简短回答是“当引入readonly 时,它会破坏向后兼容性”。长答案来自以下评论:

@ahelsbergsaid:

为了确保向后兼容性,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);

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

所以你有它。如果您想表达您对解决此问题的支持,您可能需要前往 GitHub issue 并给它一个 ? 或描述您的用例(如果它令人信服且尚未提及)。

无论如何,希望对您有所帮助;祝你好运!

【讨论】:

    【解决方案2】:

    readonly 关键字只是 ts 编译器检查。话虽如此,您是在告诉编译器 mutate 函数接受非只读参数。

    但是,如果你真的输入正确,编译器会抱怨例如

    type test = { readonly bar: number };
    
    let foo: test = {
        bar: 123
    };
    
    function iMutateFoo(foo: test) {
        foo.bar = 456; // error
    }
    

    【讨论】:

    • 我的观点是你不能保证下游的不变性,尽管他们可以强制只读编译时检查作为类型信息检查的一部分,我问他们为什么没有这样做
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-11
    • 1970-01-01
    • 2021-12-30
    • 1970-01-01
    • 2018-08-01
    • 2020-06-29
    相关资源
    最近更新 更多