typescript 从子类调用的构造函数参数推断类型

Posted

技术标签:

【中文标题】typescript 从子类调用的构造函数参数推断类型【英文标题】:typescript infer type from constructor argument called by sub class 【发布时间】:2021-05-30 03:50:31 【问题描述】:

我有一个带有一些属性/方法的类,这些属性/方法返回最初通过构造函数传递的值:

class Base 
  constructor(arg) 
     this.options = arg.options;
  

人们建议使用泛型作为打字稿等价物的此类:

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 Sub extends Base  // TS Error
    constructor() 
        super(options: foo: 123);
        this.options.foo++; // TS Error
    

Typescript 编译器对此并不满意,并希望通过该类型扩展基类。但后来我有两次信息,在超级调用和扩展符号中。解决我的问题的正确 ts 语法是什么?

(typescript playground 中的代码)

【问题讨论】:

您的游乐场链接被切断,因此代码被切断。它只是问题中的代码吗?如果是这样,我已经解决了。如果没有,请将代码同时添加到操场和问题中。 :-) 你传递的值 super 真的是编译时文字吗? FWIW,我怀疑你可以让 TypeScript 从 super 调用中推断出 Base 的类型参数。我怀疑options: foo: numberoptions: foo: 123 的近乎重复是不可避免的。 @T.J.Crowder,我修复了链接。是的,该值在代码中是固定的,不会在运行时读取/构建。它实际上定义了这个特定类具有哪些特征,并且超类在 ctor 中提供了这个参数来动态生成这些特征。 (如果这有意义的话)当通过 new 关键字调用 Base 类时,TS 能够以某种方式提取一些类型信息。所以我希望在扩展课程时同样的逻辑可以工作。但它只需要对 ts 代码进行一些更改。 【参考方案1】:

编辑:

问题不在于super(),而在于extends Base。无论如何,typescript 必须推断 Base 的泛型类型,而您不能指望 typescript 从对 super() 的调用中推断出这一点。


一开始我会建议这样做

    class Sub<T extends options: any> extends Base<T> 
    constructor() 
        super(options: foo: 123)
    

但这在a concrete instance is not allowed to be assigned to a type parameter 之后将不起作用。如果我们改为这样做,它会起作用的

    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

你知道我们为什么使用泛型吗?当我们事先不知道类型是什么时。由于在这种情况下我们确切地知道类型是什么,所以我们可以安全地这样做:

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()的东西和我们所说的泛型类型是一致的。

【讨论】:

以上是关于typescript 从子类调用的构造函数参数推断类型的主要内容,如果未能解决你的问题,请参考以下文章

如何使 TypeScript 从数组中推断参数的数量和类型

我可以从Typescript中的父类的构造函数触发子类的成员函数吗?

Typescript:Promise 的子类/扩展:不引用 Promise 兼容的构造函数值

获取函数/类构造函数的参数类型

在java语言里如何在子类中调用父类的有参构造函数

TypeScript 数据映射器函数参数从不推断