类型 A 的打字稿泛型是一个类,B 是一个实现接口<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)

形式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参数设为WorkerConstructor<T>类型。也就是说,我们希望下面的代码类型良好:

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链接到代码

最新更新