Home > Net >  TypeScript: Extract parameters from generic function type as a separate type
TypeScript: Extract parameters from generic function type as a separate type

Time:07-11

I have the following type setup coming from a library (the whole code snippet):

type ParamsMap = {
  method1: {
    prop1: string,
  },
  method2: {
    prop1: number,
    prop2: string,
  }
}
type Methods = keyof ParamsMap;
type Query = <K extends Methods>(method: K, params: ParamsMap[K]) => void;

There is a library implementation with this type, a typical call pattern:

const query: Query = (method, params) => {
  //some logic
  console.log(`${method} : ${JSON.stringify(params)}`);
};
query("method1", { prop1: "1234" });

I would like to extract parameters from query so I can call a function of Query type under the hood and perform extra processing (return type doesn't matter in this case).

I tried to apply Parameters utility class but the resulting type lacks method-prop constraint:

/* type is [method: keyof ParamsMap, params: {
    prop1: string;
} | {
    prop1: number;
    prop2: string;
}]*/
type ExtractQueryParams = Parameters<Query>
const test1 = (...params: ExtractQueryParams) => {
  console.log(`${JSON.stringify(params)}`);
}
//possible to call method1 with method2 props
test1("method1", { prop1: 1, prop2: "sdfs" });

The only way I've come up with is to define extra variable of type Query and to pass a generic to it inside typeof clause:

let q: Query;
// <K extends keyof ParamsMap> = [method: K, params: ParamsMap[K]]
type ExtractQueryParamsWithVar<K extends Methods> = Parameters<typeof q<K>>
const test2 = <K extends Methods>(...params: ExtractQueryParamsWithVar<K>) => {
  console.log(`${JSON.stringify(params)}`);
}
// now shows error
test2("method1", { prop1: 1, prop2: "sdfs" });

Is there a better way to extract these parameters with generic constraint being preserved?

CodePudding user response:

As for now, you can't extract paramteters directly. But it's possible to introduce/use an existing variable with the generic function type and utilize an instantiation expression as described by jcalz.

So basically, the ExtractQueryParamsWithVar type from the question is a way to solve it (you still have to copy the generic constraint itself, though compiler shows an error if they are omitted, obviously):

let q: Query;
// <K extends keyof ParamsMap> = [method: K, params: ParamsMap[K]]
type ExtractQueryParamsWithVar<K extends Methods> = Parameters<typeof q<K>>

Playground link

  • Related