Skip to content

unknown[] as rest params with generic parameter breaks generic inference #27439

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
skeate opened this issue Sep 28, 2018 · 4 comments
Closed
Labels
Design Limitation Constraints of the existing architecture prevent this from being fixed

Comments

@skeate
Copy link

skeate commented Sep 28, 2018

TypeScript Version: 3.1.0

Search Terms: unknown conditional rest params

Code

declare function f<T>(x: T): T;
declare function g<T>(x: T): number;

//shortened builtin: type ReturnType<F> = F extends (...args: any[]) => infer U ? U: any
type ReturnOf<F> = F extends (...args: unknown[]) => infer U ? U : never

declare const a: ReturnType<typeof g>; // number
declare const b: ReturnOf<typeof g>; // number
declare const c: ReturnType<typeof f>; // {}
declare const d: ReturnOf<typeof f>; // never

Expected behavior: d is the same as c (i.e. type {})

Actual behavior: d is type never

Playground Link

Related Issues: didn't see any; apologies if I missed it

Notes: this only happens if there's a T-typed (or union with T) parameter. Even something like Promise<T> seems to cause it to evaluate to {}. I'm not even 100% sure this is a bug (I might be missing/misunderstanding something in how unknown is handled), but it seems like in this situation it should behave the same as the any version.

@DanielRosenwasser
Copy link
Member

DanielRosenwasser commented Sep 28, 2018

This is due to two things:

  1. T has an implicit constraint of {} which is a subtype of unknown.
  2. Since parameters are contravariantly related, unknown[] is a problematic type for args in ReturnOf. This is because unknown isn't assignable to {} (remember, contravariance means we switch directions when relating two types).

You'd be best off picking the lowest bound for the type of args by using never:

type ReturnOf<F> = F extends (...args: never[]) => infer U ? U : never;

If #26796 were solved, this would've worked, but I still believe never is the best type here.

@DanielRosenwasser DanielRosenwasser added the Working as Intended The behavior described is the intended behavior; this is not a bug label Sep 28, 2018
@jack-williams
Copy link
Collaborator

jack-williams commented Sep 28, 2018

EDIT: Sorry I have successfully managed to confuse myself, feel free to ignore my question.

@DanielRosenwasser So functions are contravariant in the the domain when checking conditional types, even with strictFunctionTypes off?

// --strictFunctionTypes: off
declare function f<T>(x: T): T;
type ReturnOf<F> = F extends (...args: unknown[]) => infer U ? U : never;
type Test<F> = F extends (...args: unknown[]) => unknown ? unknown : never;

declare const d: ReturnOf<typeof f>; // never;
declare const e: Test<typeof f>; // unknown;

What I think is happening is that first U is inferred from the base constraint of T, so is {}, it then tries to unify <T>(x: T): T and the inferred type (...args: unknown[]) => {}, which actually instantiates T to be unknown by using the domain, so you get an error on the return type. I think this is why the behavior is independent of strict function checks.

@DanielRosenwasser DanielRosenwasser removed the Working as Intended The behavior described is the intended behavior; this is not a bug label Sep 29, 2018
@DanielRosenwasser
Copy link
Member

Hmm, I want to say you're right, but I'd like to check with @ahejlsberg or @weswigham first.

@ahejlsberg
Copy link
Member

@jack-williams @DanielRosenwasser That is indeed what is happening.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Design Limitation Constraints of the existing architecture prevent this from being fixed
Projects
None yet
Development

No branches or pull requests

5 participants