Description
Search Terms
variadic infer rest
Suggestion
TypeScript 4.0 added support for "Variadic Tuple Types", the key relevant change being that spreads for tuple types can be done anywhere in a tuple, not just at the end. However it appears this does not extend to rest and infer
.
It should be possible to infer an ...args
that is not at the end of a function (callable?) type.
Use Cases
I use TypeScript API clients generated from Swagger/OpenAPI specs in React code by creating hooks to make the API calls in a React safe way. Naturally I want the to pass the API method args through the hook so the input args have the correct type.
However the API methods on these clients typically have something like an options?: FetchOptionsType
at the end that shouldn't be part of the input args type. Options like these would be the purview of the hook itself, not relevant to the input arg. (...args: infer A, options? FetchOptionsType) => any
seems like it would be the natural way to infer input args without the last arg, but does not work.
Examples
type ApiMethod = (...args: any[]) => Promise<void>;
// This does not work, even in TS 4.0
type ApiMethodArgs<T> = T extends (...args: infer A, options?: any) => any
? A
: never;
// This would work but gives the wrong type
// type ApiMethodArgs<T> = T extends (...args: infer A) => any
// ? A
// : never;
// @note The following works so infer is valid when mixing rest/non-rest args but just doesn't work if rest args are not last
// type ApiMethodArgs<T> = T extends (options: any, ...args: infer A) => any
// ? A
// : never;
// External API method, all API methods follow
async function getUser(id: string, options?: any): Promise<void> { }
function callApi<AM extends ApiMethod>(method: AM) {
const commonApiOptions = {};
return async (...args: ApiMethodArgs<AM>): Promise<void> => {
await method(...args, commonApiOptions)
}
}
callApi(getUser)('asdf');
Checklist
My suggestion meets these guidelines:
- This wouldn't be a breaking change in existing TypeScript/JavaScript code
- This wouldn't change the runtime behavior of existing JavaScript code
- This could be implemented without emitting different JS based on the types of the expressions
- This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, etc.)
- This feature would agree with the rest of TypeScript's Design Goals.