I'm attempting to create a function that returns a tuple with the same length as the parameter tuple passed to it. Although I tried using generics, I am encountering an error when applying the spread operator on the result.
My goal is best illustrated through an example where I'm writing a helper function to validate and extract query parameters from an express request object.
Initially, here is an example without types:
const getQueryParams = (req: Request) => (keys) => {
const values = keys.map(key => {
const value = req.query[key];
if (value !== undefined && value !== null && typeof value === 'string') {
return value;
}
throw new Error(`Missing query param ${key}`);
});
return values;
}
To ensure that the returned values have the same length as the input tuples, I added some type helpers:
type ArrLength<T extends readonly any[]> = T['length'];
type SameLength<T extends readonly any[]> = readonly string[] & {length: ArrLength<T>};
const getQueryParams = (req: Request) => <T extends readonly string[]>(keys: T): SameLength<T> => {
const values = keys.map(key => {
const value = req.query[key];
if (value !== undefined && value !== null && typeof value === 'string') {
return value;
}
throw new Error(`Missing query param ${key}`);
}) as SameLength<T>;
return values;
}
It appears to be working partially. For instance, this snippet runs successfully:
let params = getQueryParams(req)(['token', 'user', 'count'] as const);
params = ['1'] as const; //ERROR! TypeScript identifies that parmas has a length of 3
params = ['1', '2', '3'] as const; //OK! TypeScript recognizes that parmas has a length of 3
However, when trying to call a function with the spread operator:
someApiMethod(...params)
I encounter an error stating,
Expected 3 arguments, but got 0 or more
.
If anyone knows how to fix my types or offer an alternative solution, I would greatly appreciate the assistance.
(Alternatively, if there is no resolution available, an explanation for why this issue persists along with a relevant issue in TypeScript's GitHub repository, if applicable, would suffice. I couldn't find any)