Description
Bug Report
Whenever we use a recursive generic to alter an array of functions, then use this type as a function's arguments, parameter arrow functions do not have their arguments inferred by TypeScript.
I've been trying to get this properly working to implement a pipe typings (related #30370, #25660). Which lead me to investigate why the arguments in the suggested solution are not inferred. I nailed this down to recursion type modification and made a minimal reproduction (see the code below).
If this is solved the mentioned above issues would also resolve (and probably more).
🔎 Search Terms
recursion, flow, pipe, chain, inference
🕗 Version & Regression Information
- The issue is present since version
4.1.5
(playground) when circular references were introduced that made possible to implement recursions. And still preset until4.8.0-beta
(playground).
💻 Code
Playground link with relevant code
/** Recursively replaces all items in array T with U */
type RecursiveReplace<T, U> =
T extends [any, ...infer Tail]
? [U, ...RecursiveReplace<Tail, U>]
: T;
/** Example of recursive replacement */
type Example = RecursiveReplace<[1,2,3], 3>
// ^? type Example = [3, 3, 3]
/** This should transform any function signatures passed to it to `(_: number) => void` */
function test<T extends any[]>(..._: RecursiveReplace<T, (_: number) => void>) {}
/** This works fine */
test(
(_: number) => {}
)
/** TypeScript complains about the wrong signature. This is OK too */
test(
(_: string) => {} // ERROR: Type 'number' is not assignable to type 'string'
)
/** ------------------------------------------ ↓ THE BUG ↓ ------------------------------------------- */
/** TypeScript complains about an implicit `any`. However the argument should be inferred as `number`! */
test(
(_) => {},
// ^? (parameter) _: any
);
/** -------------------------------------------------------------------------------------------------- */
🙁 Actual behavior
Recursive modification of type signatures breaks argument inference in functions.
🙂 Expected behavior
Function parameters should be properly inferred even after type signature was recursively modified.