【问题标题】:Why property in class is not read only (Typescript)为什么类中的属性不是只读的(Typescript)
【发布时间】:2021-10-16 18:38:18
【问题描述】:

为什么 PeronsImpl 类中的属性名称不是只读的,我们可以将它重新分配给创建的对象?

    interface Person {
    readonly name: string;
}

interface Greeting extends Person {
    greet(message: string): void;
}

class PersonImpl implements Greeting {
   name: string;
   age = 30;
   constructor(n: string) {
      this.name = n;
   }
   greet(message: string) {
      console.log(message + ' ' + this.name);
   }
} 

let pers = new PersonImpl("maha");
console.log(`pers : ${pers.name}`);
pers.name = "maha2";
pers.greet("hello"); //hello maha2

【问题讨论】:

    标签: javascript typescript interface readonly


    【解决方案1】:

    这有两个部分: 类属性不从它们扩展的类或接口继承类型;和 readonly 属性可以相互分配给可变属性。


    类属性不会从它们扩展的类或接口继承类型

    当您编写class Foo implements Bar {...} 时,编译器不会使用Bar 来推断Foo 的任何属性的类型。它的行为就像implements Bar 不存在一样,推断Foo 的所有类型的属性,然后检查 Bar。例如:

    interface Foo {
      x: 0 | 1;
    }
    
    class Bar implements Foo {
      x = 1; // error! x is inferred as number, not 0 | 1 
    }
    

    这是一个错误,因为class Bar { x = 1 } 将仅推断numberx,并且由于number 不能分配给0 | 1,因此这是一个错误。这种行为对很多人来说是令人惊讶和不愉快的,并且有很多 GitHub 问题要求这里提供更好的东西。请参阅 microsoft/TypeScript#10570 了解有关它的一个特别长期的未决问题。

    这意味着PersonImplname 属性是string 类型,而不是readonly

    class PersonImpl implements Greeting {
      name: string; // string, not readonly string
      //...
    }
    

    只读属性可以与可变属性相互分配

    第二个问题是编译器认为仅在其属性的readonly-ness 上不同的类型被认为是相互兼容的。您可以将{readonly x: string} 分配给{x: string},反之亦然,不会出错。请参阅 this SO answer 了解有关原因的更多信息,或参阅 microsoft/TypeScript#13347 了解要求更改此设置的功能请求。

    这意味着编译器不会发出错误,即PersonImplname 属性是可变的,而Greeting 的属性是readonly。这些类型不被认为是不兼容的。


    把它们放在一起,你就会得到你在这里看到的怪异之处。您可能会愉快地假设PersonImplname 属性是readonly,然后当您被允许为其赋值时会感到困惑。

    这里的修复是类继承类型问题的一般解决方法;为您的属性提供显式类型注释和修饰符

    class PersonImpl implements Greeting {
      readonly name: string; // annotate with readonly
      /* ... */
    }
    
    let pers = new PersonImpl("maha");
    pers.name = "maha2"; // error
    

    Playground link to code

    【讨论】:

      【解决方案2】:

      为什么 PeronsImpl 类中的属性名称不是只读的...

      因为它被类型转换为PersonImpl不是 Person。如果您希望name 为只读,您还必须在实现中将其设置为变量pers 应定义为Person 类型。

      class PersonImpl implements Greeting {
         readonly name: string; // <-- added readonly
         age = 30;
         constructor(n: string) {
            this.name = n;
         }
      

      或指定类型

      let pers:Person = new PersonImpl("maha"); // <-- added :Person
      

      【讨论】:

      • 我认为 OP 问题是为什么 implements 子句不强制 name 属性为 readonly
      • @MinusFour - 我相信 OP 在问你为什么可以根据...and we can reassign it the object created 重新分配值,我没有读到任何关于构建/转换时可能出现的 TS 错误的信息。不过,这只是我的解释。
      • 也许是这样,但问题标题询问为什么类属性不是只读的。
      猜你喜欢
      • 1970-01-01
      • 2015-07-10
      • 2011-08-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-03-05
      • 2023-02-24
      • 1970-01-01
      相关资源
      最近更新 更多