更正派生类中扩展构造函数参数的TypeScript类型



我有一个带有BaseParams构造函数参数的Base类,并且希望从Base扩展一个Derived类,该类接受ExtendedParams构造函数参数,并将其传递给super(),以及一些默认值。问题是,我似乎找不到Derived构造函数参数的访问修饰符和类型的正确组合。

到目前为止,我拥有的是:

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' }

我尝试将Derivedparams声明为protected。这就解决了问题1和问题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
}
}

问题是last: 'default'赋值没有发生,因为protected生成的this.params = params赋值覆盖了传递给super()params值,所以d.inspect()只输出{ first: 'Mike', whatever: 'Wrong' }

我尝试省略params的访问修饰符。这导致正确的输出{ first: 'Mike', last: 'default', whatever: 'Wrong' },但也导致this.params.last被标记为错误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
}
}

是否有一些TypeScript魔术可以通知编译器,在Derived类中,this.paramsExtendedParams类型,默认值将传递给super()调用,之后this.params不会被覆盖?

但是从Derived访问Base.params,它被明确地键入为BaseParams

如果您希望params属性更改派生类中的类型,则需要一个泛型基类型:

// <P = BaseParams> allows to instantiate Base with BaseParams as default type.
class Base<P = BaseParams> {
constructor(protected params: P) {}
/* ... */
}
class Derived extends Base<ExtendedParams> {
constructor(params: ExtendedParams) {
super({ first: 'John', last: 'default', ...params });  // override default params with specified ones
this.params.last;                // OK
this.params.whatever = 'Wrong';  // Wrong
}
}

最新更新