Home > Net >  Infer parameters from return type of generic
Infer parameters from return type of generic

Time:10-05

I'm creating a function whereby the first parameter is an array of "services", and the second parameter infers the return type of those services. For example:

const serviceOne = createService([], () => Promise.resolve({} as Service1));
const serviceTwo = createService([], () => Promise.resolve({} as Service2));

const serviceThree = createService(
  [serviceOne, serviceTwo],
  (one, two) => Promise.resolve({}), // one should be inferred as Service1, two should be inferred as Service2
);

How can I modify my function signature to achieve this inference? At the moment, I have them typed as any

function createService<T extends Service<any>[], U>(deps: T, factory: (...args: any[]) => Promise<U>) {
  return {} as Service<U>;
}

type Service<U> = {
  instance: U
};

Playground

CodePudding user response:

You can first need to change the constraint to T to get typescript to infer a tuple type instead of an array type. To do this, we just need to add a union with the empty tuple to the constraint ([] |). This will set typescript in the right state to infer tuples

We can then use a mapped type to map from a tuple containing Service<any> to a tuple containing the service types:

const serviceThree = createService(
  [serviceOne, serviceTwo],
  (one, two) => Promise.resolve({} as Service3), // one is Service1, two is Service2
);

type GetServiceType<T extends Service<any>[]> = unknown [] & {
  [P in keyof T]: T[P] extends Service<infer R> ? R: never
}
function createService<T extends [] | Service<any>[], U>(deps: T, factory: (...args: any[] & GetServiceType<T>) => Promise<U>) {
  return {} as Service<U>;
}

Playground Link

  • Related