Closed
Labels
Design LimitationConstraints of the existing architecture prevent this from being fixedConstraints of the existing architecture prevent this from being fixed
Description
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>; // neverExpected behavior: d is the same as c (i.e. type {})
Actual behavior: d is type never
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.
Metadata
Metadata
Assignees
Labels
Design LimitationConstraints of the existing architecture prevent this from being fixedConstraints of the existing architecture prevent this from being fixed
Activity
DanielRosenwasser commentedon Sep 28, 2018
This is due to two things:
Thas an implicit constraint of{}which is a subtype ofunknown.unknown[]is a problematic type forargsinReturnOf. This is becauseunknownisn'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
argsby usingnever:If #26796 were solved, this would've worked, but I still believe
neveris the best type here.jack-williams commentedon Sep 28, 2018
EDIT: Sorry I have successfully managed to confuse myself, feel free to ignore my question.
Daniel Rosenwasser (@DanielRosenwasser) So functions are contravariant in the the domain when checking conditional types, even with strictFunctionTypes off?
What I think is happening is that first
Uis inferred from the base constraint ofT, so is{}, it then tries to unify<T>(x: T): Tand the inferred type(...args: unknown[]) => {}, which actually instantiatesTto beunknownby 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 commentedon Sep 29, 2018
Hmm, I want to say you're right, but I'd like to check with Anders Hejlsberg (@ahejlsberg) or Wesley Wigham (@weswigham) first.
ahejlsberg commentedon Sep 29, 2018
Jack Williams (@jack-williams) Daniel Rosenwasser (@DanielRosenwasser) That is indeed what is happening.