A 类型的 Typescript 泛型是 Class,B 是实现接口 <A> 的 class

Typescript generics for type A is a Class and B is a class that implements Interface<A>

我想要一个类型安全的注册函数,它注册一个带有两个参数和两个泛型类型的 WorkerOf,这样消费者就必须用相应的 WorkerOfA 注册一个 ClassA。

type Worker<Payload> = { exec: (payload: Payload) => Promise<void> };
type Constructor<Payload> = new (...args: any[]) => Payload;
type WorkerConstructor<Payload extends Constructor<Payload>> = new (
  ...args: any[]
) => Worker<Payload>;

function register<Payload extends Constructor<Payload>>(
  _pyd: Payload,
  _wkr: WorkerConstructor<Payload>
) {}

class PayloadOne {}
class PayloadTwo {}
class WorkerOne implements Worker<PayloadOne> {
  constructor() {}
  async exec(_payload: PayloadOne): Promise<void> {}
}

// Expected to work because WorkerOne implements Worker<PayloadOne>
register(PayloadOne, WorkerOne);
// Expected to fail because WorkerOne doesn't implements Worker<PayloadTwo>
register(PayloadTwo, WorkerOne);

在这两种情况下,我都收到以下打字稿错误:

Argument of type 'typeof PayloadOne' is not assignable to parameter of type 'Constructor<typeof PayloadOne>'. Property 'prototype' is missing in type 'PayloadOne' but required in type 'typeof PayloadOne'.ts(2345)

您的 generic constraints 形式 T extends Constructor<T> 并不是您希望他们表达的意思。如果您需要 T 作为构造函数类型,T extends Constructor<any> 就足够了。否则,T extends Constructor<T> 意味着 T 是一个构造函数类型,其实例本身就是 T。所以它是一个构造函数,构造函数,构造函数,构造函数,构造函数,...

对于您提供的示例,您甚至不需要 T extends Constructor<any>。相反,让 T 是任意类型,并且 register()_pyd 参数是 Constructor<T> 类型,而 _wkr 是 [=25] 类型=].也就是说,我们希望下面的代码是 well-typed:

new _wkr().exec(new _pyd())

看起来像这样:

type Worker<T> = { exec: (payload: T) => Promise<void> };
type Constructor<T> = new (...args: any[]) => T;
type WorkerConstructor<T> = new (...args: any[]) => Worker<T>;

function register<T>(
    _pyd: Constructor<T>,
    _wkr: WorkerConstructor<T>
) { }

所有编译都很好,请注意 T 不受任何限制。让我们确保它在您调用 register():

时有效
class PayloadOne { a = 1 }
class PayloadTwo { b = 2 }    
class WorkerOne implements Worker<PayloadOne> {
    constructor() { }
    async exec(_payload: PayloadOne): Promise<void> { }
}

register(PayloadOne, WorkerOne); // okay
register(PayloadTwo, WorkerOne); // error
// Argument of type 'typeof PayloadTwo' is not assignable
// to parameter of type 'Constructor<PayloadOne>

看起来不错!

Playground link to code