Skip to content

Can not call a generic function as an call "effect" (pattern in in redux-saga) #40798

Closed

Description

TypeScript Version: 4.0.2

Code

interface Foo {
  bla: string;
}

declare function map<T, R>(value: T[], transform: (t: T) => R): R[];

declare const foos: Foo[];

declare function call<Fn extends (...args: any[]) => any>(
  fn: Fn,
  ...args: Parameters<Fn>
): ReturnType<Fn>;

const a = call(map, foos, (foo: Foo) => foo.bla);

Expected behavior:
I expect this to give no compile errors.

Actual behavior:

Argument of type '(foo: Foo) => string' is not assignable to parameter of type '(t: unknown) => unknown'. Types of parameters 'foo' and 't' are incompatible. Type 'unknown' is not assignable to type 'Foo'

Playground Link:
Playground

Activity

  1. jack-williams commented on Sep 27, 2020

    @jack-williams
    Collaborator

    This falls largely under the same design limitation as described here: #31811.

    When using generics a good guideline to follow is to push generic parameters down such that they quantifier over as little structure as necessary. I think the best way to write this is:

    declare function call<P extends unknown[], R>(
      fn: (...args: P) => R,
      ...args: P
    ): R;
  2. MartinJohns commented on Sep 27, 2020

    @MartinJohns
    Contributor

    Jack Williams (@jack-williams) was a minute faster than me. :-D

    #38964 and #37181 are also related.

  3. kasperpeulen commented on Sep 28, 2020

    @kasperpeulen
    Author

    Jack Williams (@jack-williams) Ah that is interesting thanks!

    The next step would be if the callback (the third argument), could be inferred from the first two arguments.

    interface Foo { bla: string; }
    declare function map<T, R>(value: T[], transform: (t: T) => R): R[];
    declare const foos: Foo[];
    
    declare function call<P extends unknown[], R>(
      fn: (...args: P) => R,
      ...args: P
    ): R;
    
    // Object is of type 'unknown'.    vvv
    const a = call(map, foos, (foo) => foo.bla);

    This fails. With the error in the comment. However, if I write it like this:

    declare function call<X, P extends unknown[], R>(
      fn: (x: X, ...args: P) => R,
      x: X,
      ...args: P
    ): R;
    
    // Compiles, but a inferred as unknown[]
    const a = call(map, foos, (foo) => foo.bla);

    It does compile, if I hover over foo it is of type Foo, but a is inferred as unknown[]. Is this a "legit" bug?

  4. RyanCavanaugh commented on Sep 28, 2020

    @RyanCavanaugh
    Member

    Gonna have to link #30134 for that one

  5. typescript-bot commented on Oct 1, 2020

    @typescript-bot
    Contributor

    This issue has been marked as a 'Duplicate' and has seen no recent activity. It has been automatically closed for house-keeping purposes.

  6. locked as resolved and limited conversation to collaborators on Oct 21, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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