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