2

Why property name in class PeronsImpl is not read only and we can reassign it the object created ?

    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
0

2 Answers 2

4

There's two parts to this: Class properties do not inherit typings from the classes or interfaces they extend; and readonly properties are mutually assignable to and from mutable properties.


Class properties do not inherit typings from the classes or interfaces they extend

When you write class Foo implements Bar {...}, the compiler does not use Bar to infer the types of any of Foo's properties. It behaves as if implements Bar were not present, infers all the types of Foo's properties, and then just checks against Bar. For example:

interface Foo {
  x: 0 | 1;
}

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

This is an error because class Bar { x = 1 } would infer just number for x, and since number is not assignable to 0 | 1, it's an error. This behavior is surprising and unpleasant to lots of folks, and there are quite a few GitHub issues requesting something better here. See microsoft/TypeScript#10570 for one particularly longstanding open issue about it.

That means the name property of PersonImpl is of type string, and is not readonly:

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

Readonly properties are mutually assignable to and from mutable properties

The second issue is that types which differ only by the readonly-ness of their properties are considered to be mutually compatible by the compiler. You can assign a {readonly x: string} to an {x: string} and vice versa without error. See this SO answer for more information about why that is, or see microsoft/TypeScript#13347 for a feature request asking this to be changed.

So that means the compiler does not issue an error that PersonImpl's name property is mutable while Greeting's is readonly. Those types are not considered incompatible.


Put those together, and you get the weirdness you see here. You might happily assume that PersonImpl's name property is readonly, and then get confused when you are allowed to assign a value to it.

The fix here is the general workaround to the class inherited typing issue; give explicit type annotations and modifiers to your properties:

class PersonImpl implements Greeting {
  readonly name: string; // annotate with readonly
  /* ... */
}

let pers = new PersonImpl("maha");
pers.name = "maha2"; // error

Playground link to code

Sign up to request clarification or add additional context in comments.

Comments

1

Why property name in class PeronsImpl is not read only...

Because it is typecast as PersonImpl and not Person. If you want name as readonly you must also make it so in the implementation or variable pers should be defined as type Person.

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

or specify type

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

3 Comments

I think OP question is why the implements clause doesn't force name property to be readonly.
@MinusFour - I believe the OP is asking why you can reassign the value based on ...and we can reassign it the object created, I did not read anything about a possible TS error on building/transpiling. That is just my interpretation though.
Maybe so but question title asks why the class property isn't read only.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.