【问题标题】:How to pass a newable `this` to a static method from a static method?如何将新的`this`从静态方法传递给静态方法?
【发布时间】:2019-08-09 05:29:09
【问题描述】:

如何将可更新的this 从静态方法传递给静态方法?

TypeScript Playground

abstract class Model {
  public static convert<T extends Model>(model: new () => T, data: any | any[]) { 
    return new model()
  }

  public static all<T extends Model>(): Promise<[]> {
    let items: any[] = []
    return Model.convert(this, items)
                      // ^--- Error is here
  }
}

生成的 JavaScript 工作正常,我得到了一个 A 的实例,但是 typescript 抱怨这个错误:

“typeof Model”类型的参数不能分配给“new () => Model”类型的参数。

class Model {
    static convert(model, data) { return new model() }
    static all() {
        let items = [];
        return Model.convert(this, items);
    }
}

class A extends Model { }

console.log(A.all(), A.all().constructor.name);

【问题讨论】:

    标签: javascript typescript


    【解决方案1】:

    如果Model 不是abstract,这通常会起作用。如果Model 不是抽象的this(类型为typeof Model)将有new () =&gt; Model 构造函数,但由于它是抽象的,它没有可调用的构造函数。

    简单的解决方法是在静态方法中为this添加注解:

    abstract class Model {
      public static convert<T extends Model>(model: new () => T, data: any | any[]): T[] { return null!; }
    
      public static all<T extends Model>(this: new () => T): Promise<T[]> {
        let items: any[] = []
        return Promise.resolve(Model.convert(this, items));
      }
    }
    
    class A extends Model { }
    
    
    console.log(Model.all()) // err since Model does not have a ctor
    console.log(A.all(), A.all().constructor.name)
    

    Play

    这将使all 无法调用Model,这可能是您想要的。

    编辑

    由于在您的实际用例中您想从其他静态方法调用静态方法,我们需要为this 提供稍微复杂的注解。以前的版本只保留构造函数签名,没有任何静态成员。您需要注解中typeof Model 表示的静态成员。最简单的方法是在与我们之前定义的构造函数签名((new () =&gt; T))的交集处添加typeof Model,基本上是向抽象类添加构造函数。

    
    type NonAbstracModel<T extends Model> = (new () => T) & typeof Model
    abstract class Model {
      public static convert<T extends Model>(model: NonAbstracModel<T>, data: any | any[]): T { return new model() }
    
      public static all<T extends Model>(this: NonAbstracModel<T>): T {
        let items: any[] = []
        return Model.convert(this, items)
      }
    
      public static find<T extends Model>(this: NonAbstracModel<T>, primaryKey: string | object) { }
    
      public static firstOrFail<T extends Model>(this:NonAbstracModel<T>) {
        this.find('abc')
      }
    
    }
    
    class A extends Model {}
    
    console.log(A.all(), A.all().constructor.name)
    

    【讨论】:

    • 是的,最后一句话是真的,我不要Model.all()
    • 我在另一个方法中有这个,所以我将它添加到方法参数this: new() =&gt; T,然后调用该方法的地方现在得到一个错误this.find(),它说这个:@987654341 @
    • @GetOffMyLawn 修改答案以解决此用例
    • @GetOffMyLawn 很抱歉没有替换所有参数类型,已修复。类名表示的类型是实例类型。 typeof ClassName代表类本身的类型,(即它是一个对象类型,有静态成员和返回实例类型的构造函数)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多