Skip to content

Cannot use Parameters in generic function #39378

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
akwodkiewicz opened this issue Jul 2, 2020 · 2 comments
Closed

Cannot use Parameters in generic function #39378

akwodkiewicz opened this issue Jul 2, 2020 · 2 comments
Labels
Working as Intended The behavior described is the intended behavior; this is not a bug

Comments

@akwodkiewicz
Copy link

akwodkiewicz commented Jul 2, 2020

I cannot use generic fn's Parameters when calling fn.

TypeScript Version: 3.9.2

Search Terms:
wrong generic function infer parameters

Code

const functionDict = {
    A: (a: any) => ({ a }),
    B: (a: any, b: string) => ({ a, b }),
    C: (a: any, b: string, c: string) => ({ a, b, c }),
};

type ValueOf<T> = T[keyof T];

export function foo<F extends ValueOf<typeof functionDict>>(
    fn: F,
    pp: Parameters<F>,
): void {
    fn(...pp);
}

Expected behavior:
No error.

Actual behavior:
Error: Expected 3 arguments, but got 0 or more.(2556)
input.ts(4, 9): An argument for 'a' was not provided

Playground Link: https://www.typescriptlang.org/play/#code/MYewdgzgLgBAZgVzMKBLcARVKYF4YDeAsAFAzkwCCAXDABQCGtDYAngJR4B89BMDMAL7sANKQowAQrUbM2ImACNa0AE6owAc064edPgwWKho8RQDCMpv3lKVUdVoXB7j7d178jzk2JKCAblJSKFYABwBTGAA1BgAbBAiAeTgAHgAVHnx0gG0AawjWEDgYdIBdIJJSCIAPMJBVWERkNHB4EBBUgDEYWqgIsAATCBj4xJTU0Mji+CQUdDAsFC4uOjNyODBaLr8JMLDaAAUGVQYAWwj+1Qhurj92WgA3EFRBwnX4MDoAOl-99kqglIQA

Related Issues:

@akwodkiewicz akwodkiewicz changed the title Wrong generic function param type inferrence Wrong generic function param type inference Jul 2, 2020
@akwodkiewicz akwodkiewicz changed the title Wrong generic function param type inference Cannot use Parameters in generic function Jul 2, 2020
@jcalz
Copy link
Contributor

jcalz commented Jul 4, 2020

The generic constraint T extends X | Y does not mean "T extends X or T extends Y". It could be the case that T is X | Y, which extends neither X nor Y in general. Without a feature like #27808 there is no way in TypeScript to express a constraint of the form "T extends exactly_one_member_of X | Y".

In foo() the generic type F could turn out to be, for example, typeof functionDict.A | typeof functionDict.B:

const fn = Math.random() < 0.5 ?
    (a: any) => ({ a: 123 }) :
    (a: any, b: string) => ({ a: 123, b: b.toUpperCase() });
foo(fn, ["a"]); // 50% chance of "b is undefined" error

So it is technically unsound to allow fn(...pp) inside the function implementation without error. Of course, with some refactoring you could get the compiler to accept what you're doing inside the implementation:

function goo<A extends any[]>(fn: Extract<ValueOf<typeof functionDict>, (...a: A) => any>, pp: A) {
    fn(...pp); // okay
}

goo(fn, ["a"]); // error at compile time now

but that's not exactly what you're looking for, I gather.

Playground link to code

@RyanCavanaugh RyanCavanaugh added the Working as Intended The behavior described is the intended behavior; this is not a bug label Jul 8, 2020
@typescript-bot
Copy link
Collaborator

This issue has been marked 'Working as Intended' 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
Labels
Working as Intended The behavior described is the intended behavior; this is not a bug
Projects
None yet
Development

No branches or pull requests

4 participants