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

Time:05-27

I would like to have a type safe register function that registers a WorkerOf with two arguments and two generic types so that consumers have to register a ClassA with the corresponding WorkerOfA.

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);

In both cases I am getting the following typescript error:

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)

CodePudding user response:

Your generic constraints of the form T extends Constructor<T> don't mean what you want them to mean. If you need T to be a constructor type, T extends Constructor<any> would be sufficient. Otherwise, T extends Constructor<T> means that T is a constructor type whose instances are themselves T. So it's a constructor that constructs constructors that construct constructors that construct constructors that...

  • Related