![](/img/trans.png)
[英]Declare a constructor to correctly infer generic type from (keyof) argument in TypeScript
[英]typescript infer type from constructor argument called by sub class
我有一个 class 具有一些属性/方法,这些属性/方法返回最初通过构造函数传递的值:
class Base {
constructor(arg) {
this.options = arg.options;
}
}
人们建议使用 class 和 generics 作为 typescript 等效项:
class Base<T extends {options: any}> {
options: T["options"];
constructor(arg: T) {
this.options = arg.options;
}
}
// works fine with instantiation
const inst = new Base({options: {foo: 123}});
inst.options.foo++; // ok
inst.options.bar; // TS Error
现在我有一个子 class 调用超类的构造函数并传递这些选项:
class Sub extends Base { // TS Error
constructor() {
super({options: {foo: 123}});
this.options.foo++; // TS Error
}
}
Typescript 编译器对此不满意,并希望通过该类型扩展 Base class。 但后来我有两次信息,在超级调用和扩展符号中。 解决我的问题的正确 ts 语法是什么?
(代码在typescript 操场上)
编辑:
问题不在于super()
而在于extends Base
。 无论如何, typescript 必须推断出 Base 的泛型类型,您不能指望 typescript 从对super()
的调用中推断出这一点。
起初我会建议这样做
class Sub<T extends {options: any}> extends Base<T> {
constructor() {
super({options: {foo: 123}})
}}
但这不起作用,因为不允许将具体实例分配给类型参数。 如果我们改为这样做,它会起作用
class Sub<T extends {options: any}> extends Base<T> {
constructor(arg: T) {
super(arg)
}}
const inst2 = new Sub({options: {foo: 123}})
inst2.options.foo++; // ok
我认为正确的解决方案是简单地这样做
class Sub extends Base<{options: any}> {
constructor() {
super({options: {foo: 123}})
}}
但是,仍然存在问题。
const inst2 = new Sub();
inst2.options.foo++; //options is any which makes sense, we said that options is any above
你知道我们为什么使用 generics 吗? 当我们事先不知道类型是什么时。 由于在这种情况下我们确切地知道类型是什么,所以我们可以安全地这样做:
class Sub extends Base<{ options: {foo: number} }> {
// or even class Sub extends Base<{ options: {foo: 123} }> {
constructor() {
super({options: {foo: 123}});
this.options.foo++;
}
}
const inst2 = new Sub();
inst2.options.foo++;
这样做可以吗? 当然,如果我们将选项以外的东西传递给Base
,它会触发警告。 所以我们满足Base
的要求,同时确保我们传递给super()
的内容与我们所说的泛型类型一致。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.