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