Skip to content

Function argument type inference in recursively modified types #50468

Closed
@Azarattum

Description

@Azarattum

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 until 4.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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    DuplicateAn existing issue was already created

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions