I have a Base class with a BaseParams constructor parameter, and want to extend a Derived class from Base, that takes an ExtendedParams constructor parameter, and passes it to super(), along with some defaults. The problem is that I can't seem to find the right combination of access modifiers and types for the Derived constructor parameter.
Here's what I have so far:
interface BaseParams {
first: string;
}
interface ExtendedParams extends BaseParams {
last?: string;
}
class Base {
constructor(protected params: BaseParams) {}
inspect(): void {
console.log(this.params);
}
}
class Derived extends Base {
constructor(??? params ???) {
super({ first: 'John', last: 'default', ...params }); // override default params with specified ones
this.params.last; // #1 - this should not generate any compile errors
this.params.whatever = 'Wrong'; // #2 - TS should flag this as not existing on type ExtendedParams
}
}
const d = new Derived({ first: 'Mike' });
d.inspect(); // #3 - should output { first: 'Mike', last: 'default', whatever: 'Wrong' }
I tried declaring the Derived params as protected. That solves #1 and #2.
class Derived extends Base {
constructor(protected params: ExtendedParams) {
super({ first: 'John', last: 'default', ...params });
this.params.last; // #1 - ok, no error
this.params.whatever = 'Wrong'; // #2 - ok, flagged: `whatever` doesn't exist on type ExtendedParams
}
}
The problem is that the last: 'default' assignment doesn't take place because protected generates a this.params = params assignment that overwrites the params value passed to super(), so d.inspect() outputs only { first: 'Mike', whatever: 'Wrong' }.
I tried omitting the access modifier for params. This leads to the correct output { first: 'Mike', last: 'default', whatever: 'Wrong' }, but also to this.params.last being flagged as an error, does not exist on type 'BaseParams'.
class Derived extends Base {
constructor(params: ExtendedParams) {
super({ first: 'John', last: 'default', ...params });
this.params.last; // #1 - wrong ly flagged
this.params.whatever = 'Wrong'; // #2 - ok, flagged
}
}
Is there some TypeScript magic to inform the compiler that in the Derived class, this.params is of ExtendedParams type, and the defaults get passed to the super() call and this.params is not overwritten afterwards?
But from
Derivedyou accessBase.paramswhich is clearly typed asBaseParams.If you want the
paramsproperty to change type in derived classes, you'd need a generic base type: