I'm interpreting the question as:
Why does merging an interface declaration into the instance side of a class declaration not cause the compiler to warn when the interface-declared properties are not initialized in the class, even when the --strictPropertyInitialization compiler option is enabled?"
And the answer is:
The use case for declaration merging into a class is to patch an existing class from the outside. Generally speaking, if you augment the class inferface with a new property or method from the outside, you will also initialize the property or method from the outside. So you'd start with the original class declaration:
class Dog {
constructor() { }
}
And then externally you augment the interface and also implement the added properties:
interface Animal {
a: string;
b: string;
}
interface Dog extends Animal {
c: string;
}
// implementation
Dog.prototype.a = "defaultA";
Dog.prototype.b = "defaultB";
Dog.prototype.c = "defaultC";
If you do that, it will work as expected:
const d = new Dog();
console.log(d.b); // "defaultB"
d.b = "newB";
console.log(d.b); // "newB"
Meanwhile, the use case for the --strictPropertyInitialization compiler option is to verify that the properties declared in the class itself are properly initialized. This is a separate use case from declaration merging; any properties you need to definitely initialize in the class body should also be declared in the class body.
So that's the answer to the question as asked. It seems you have an underlying need to create a class constructor from an interface without re-declaring the properties in the class, and your attempt to do this was with declaration merging... which is, unfortunately, not the right tool for the job (at least as of TypeScript 4.9).
There are other approaches; sometimes I use what I call an "assigning constructor" factory which only needs to be implemented once:
function AssignCtor<T extends object>(): new (init: T) => T {
return class { constructor(init: any) { Object.assign(this, init); } } as any;
and then you can use it to generate class constructors:
interface IDog {
a: string;
b: string;
c: string;
}
class Dog extends AssignCtor<IDog>() {
bark() {
console.log("I SAY " + this.a + " " + this.b + " " + this.c + "!")
}
};
const d = new Dog({ a: "a", b: "b", c: "c" });
d.bark(); // I SAY a b c!
This may or may not meet your needs, and it's out of scope for the question as asked in any case. My point is just that you will probably want to look somewhere other than declaration merging to scratch this particular itch.
Playground link to code
class Dog extends Animal(orimplements Animal) and then initialize properties in the class itself. Does that fully address the question? If so I could write up an answer explaining; if not, what am I missing?Animalis not a superclass then you can't extend it. What do you mean by "reuse" the properties? As asked, the question wants to know why declaration merging doesn't require class property initialization, now how to work around it, so... would you accept an answer saying something like "--strictPropertyInitializationis not intended to warn about anything that might be externally merged (presumably those properties would be externally initialized also)" along with links to sources? Or am I missing something?