Skip to content

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

Closed
@kasperpeulen

Description

@kasperpeulen

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

jack-williams

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;
MartinJohns

MartinJohns commented on Sep 27, 2020

@MartinJohns
Contributor

@jack-williams was a minute faster than me. :-D

#38964 and #37181 are also related.

kasperpeulen

kasperpeulen commented on Sep 28, 2020

@kasperpeulen
Author

@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?

RyanCavanaugh

RyanCavanaugh commented on Sep 28, 2020

@RyanCavanaugh
Member

Gonna have to link #30134 for that one

typescript-bot

typescript-bot commented on Oct 1, 2020

@typescript-bot
Collaborator

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

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

        Participants

        @kasperpeulen@jack-williams@MartinJohns@RyanCavanaugh@typescript-bot

        Issue actions

          Can not call a generic function as an call "effect" (pattern in in redux-saga) · Issue #40798 · microsoft/TypeScript