【问题标题】:readonly properties is working partially in typescript?只读属性在打字稿中部分工作?
【发布时间】:2021-10-11 21:15:52
【问题描述】:

让我们看看这段代码

interface ImmutableValue<T> {
    readonly value: T;
}

let i: ImmutableValue<string> = { value: "hi" };
i.value = "Excellent, I can't change it"; // compile-time error

以上内容非常简单,我们有一个接口ImmutableValue,由于i 正在实现该接口,i.value 将得到编译错误

现在考虑下面的代码

interface Greetable {
  readonly name: string;
}

class Person implements Greetable {
  name: string;

  constructor(n: string) {
    this.name = n;
  }
}

let user1 = new Person('isaac');

user1.name = 'jon'
console.log(user1)

对于上面的代码,显然Person 正在实现Greetable,它的namereadonlyuser1.name = 'jon' 是一个值重新分配,我们应该得到一个错误。但是 TS 编译得很好,知道为什么吗?

【问题讨论】:

  • Person extends Greetable,包括允许写名字。
  • @jonrsharpe:我不认为我们可以extends 一个接口..
  • 我不是指extends,我指的是添加行为。任何需要 Greetable、具有可读名称属性的东西,仍然可以使用 Person。他们无法通过该接口进行写入,另一个消费者通过 Person 可能访问相同值的事实是无关紧要的。

标签: javascript typescript oop interface


【解决方案1】:

TypeScript 在确定两种类型是否兼容时会忽略readonly,因此PersonGreetable 兼容,尽管Greetable 使name readonlyPerson 不兼容。来自this page on readonly

管理对readonly 暗示的期望很重要。在 TypeScript 的开发期间发出关于如何使用对象的意图很有用。 TypeScript 在检查这两种类型是否兼容时不会考虑这两种类型的属性是否为readonly,因此readonly 属性也可以通过别名进行更改。

(我的重点)

不过,更一般地说,子类型可以在其超类型之上添加功能。作为jonrsharpe points out in a comment,任何使用Greetable 的代码仍然可以使用PersonGreetable 引用 Person 的代码将无法通过该引用更改 name

function example(g: Greetable) {
    g.name = "example"; // Error
}
example(new Person("Joe"));

但是公开readonly 并不能保证某些东西不会改变,只是具有readonly 访问权限的代码不能改变它,这是微妙的不同。

【讨论】:

  • hmm 有趣...我对interface 的理解是,它用于强制Person 具有与Greetable 相似的签名。如果是extends的继承,关于定义覆盖的部分我可以理解,但是这里和继承无关是不是
  • @Isaac - 覆盖与继承有关,是的,虽然我认为覆盖与这个特定方面有点相切,我可能应该将它改写为答案。 :-)
猜你喜欢
  • 1970-01-01
  • 2021-09-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多