网站搜索

javascript - Typescript:调用具有 `this` 参数的静态函数


我目前在 TypeScript 上遇到了瓶颈。

基本上,我想从一个继承自特定抽象类的类中调用一个静态函数。

我收到以下错误

The 'this' context of type 'typeof A' is not assignable to method's 'this' of type 'AStatic<AStatic<unknown>>'. Cannot assign an abstract constructor type to a non-abstract constructor type.

这里是一个 Typescript 游乐场的链接

这是代码:

type AStatic<S extends A> = { new(): S };

abstract class A {
  static callStatic<S extends AStatic<S>>(this: AStatic<S>) {
    console.log('hey')
  }
}

class B extends A {
}


class D extends A {
}

class C {
  aType: typeof A;
  constructor(type: typeof A) {
    this.aType = type;
    this.aType.callStatic(); // error is here
  }
}

const c = new C(B);
const c_2 = new C(D);

我唯一能让它在 TypeScript 中编译的方法是传递 any 而不是 typeof A。这真是遗憾,因为我无法从 IDE 获取对 A 的函数的支持。

请注意,我无法控制类 A 和类型 AStatic,因为它们来自外部库。

答案#1

你很接近了!看看你对 A 的伪定义吧:

abstract class A {
  static callStatic<S extends AStatic<S>>(this: AStatic<S>) {
  //                                      ^^^^^^^^^^^^^^^^
  //           the `this` parameter must be type AStatic<A>

并查看 AStatic:

type AStatic<S extends A> = { new(): A };
//                            ^^^^^ - type must have a constructor, 
//                                      which rules out abstract classes.

这排除了将 typeof A 作为 this 参数的可能性,因为它是 abstract 的。我们可以尝试直接使用 AStatic:

class C {
  aType: AStatic<A>;
  constructor(type: AStatic<A>) {
    this.aType = type;
    this.aType.callStatic();
    //         ^^^^^^^^^^ - Property 'callStatic' does not exist on type 'AStatic<A>'
  }
}

但是 callStatic 在 AStatic 上未定义。解决方案是使用交叉类型:

class C {
  aType: AStatic<A> & typeof A
  constructor(type: AStatic<A> & typeof A) {
    this.aType = type;
    this.aType.callStatic() // works!
  }
}

正如 MunsMan 所指出的,除非你在派生类型上重写 callStatic,否则根本不需要传递 typeof A:

const c = new C(B);
c.callStatic(); // hey
B.callStatic(); // hey
D.callStatic(); // hey

换句话说,只要你有一个 A 的非抽象版本,你就可以在该类型上调用 callStatic(或任何静态方法/属性),它每次都会以相同的方式工作!

答案#2

你正在尝试调用A的一个显式实例,这是不必要的。

type AStatic<S extends A> = { new(): A };

abstract class A {
    static callStatic<S extends AStatic<S>>(this: AStatic<S>) {
        console.log('hey')
    }
}

class B extends A {

}

class C {
    aType: typeof A;
    constructor(type: typeof A) {
        this.aType = type;
        B.callStatic()
    }
}

const c = new C(B);

因为方法 callStatic 是静态的,你可以直接调用 B 中这个方法的实现。