-
Notifications
You must be signed in to change notification settings - Fork 12.8k
Infer type in conditional cannot unify generics #22617
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
Comments
Repeating my comments from #22615 as they apply equally here: It is effectively a design limitation. We have the concept of instantiating a generic function type in the context of a non-generic function type (a form of unification), but we currently don't do that in conditional types. Instead, function type parameters are erased to their constraints and we infer from those. In the example above, that causes us to infer The proper fix for this would be have type inference perform instantiation of a source type in the context of a target type when the source type is a generic function type. |
It's a design limitation, but Suggestion and Need proposal were added instead of closing. Does this mean there's a slim chance this could land eventually? This specific use case of a generic input type mapped onto the output is really common and this issue is stopping quite a few use cases from being typed properly. |
Any new thoughts/insights? IMHO, now that v3.0 is out, this issue has become more interesting. It looks like this issue is the cause of this behavior: type BindConsumer<T, M extends <A>(a: A) => any> =
M extends ((a: T) => infer U)
? U
: never
const a: BindConsumer<number, <U>(a: U) => { boxed: U }> = {
boxed: 2, // infers the type: { boxed: {} }
} If (strong if) this is a bug/potential feature, then fixing it will allow for all sorts of neat types like: // Can be used for function declarations like zip and even conditional mapping.
// mapped types on tuples could also make this work.
type MapTuple<Tuple extends any[], Mapping extends <T>(a: T) => any> = never // long and tedious
// Good for all manner of composition/piping.
// Folds the tuple's types into one by inferring the return of Join.
// mapped types on tuples probably isn't good enough for this?
type FoldTuple<Tuple extends any[], Join extends <T, U>(a: T, b: U) => any, Seed> = never // longer and more tedious Though, any type made this way can be expressed, albeit more verbosely. |
Hi, I'll add a simple example related to this: type GenericReturnType<T, TInput> = T extends (_: TInput) => infer TResult? TResult: never;
// Gives { x: {}; }
type Box = <T>(_: T)=> { value: T };
type _test1 = GenericReturnType<Box, number>;
// Gives {x: number; }
type AltBox<T> = (_: T)=> { value: T };
type _test2 = GenericReturnType<AltBox<number> | AltBox<string>, number>; |
@ahejlsberg The fix for this was planned to be in TypeScript 2.9 milestone, but then it has been removed (judging from #22615 history). Is there any plan to include this in the milestones of 4.1, 4.2 or higher versions? Since it might have many use cases for higher order functions |
One of the use cases that can be achieved by fixing this limitation: const getRef = <T extends any>(val: T) => {
return {
current: val,
};
};
const getWrapInValueFn = <Fn extends (arg: any) => any>(fn: Fn) => {
return <A extends Parameters<Fn>[0]>(
arg: A
): { value: Fn extends (arg: A) => infer R ? R : never } => {
return {
value: fn(arg),
};
};
}; const wrapInValue = getWrapInValueFn(getRef);
const data = wrapInValue(5); // infsers { value: { current: unknown; }; } instead of { value: { current: number; }; } |
TypeScript Version: 2.8.0-dev.20180315
Search Terms:
infer conditional unify generic function
Code
Expected behavior:
All
A
andB
types are inferred tostring[]
. For typesB
, the type parameterU
should be unified withstring
.Actual behavior:
All
B
types are inferred to{}[]
.Related Issues:
#22615 (different problem, but similar input)
The text was updated successfully, but these errors were encountered: