- Notifications
You must be signed in to change notification settings - Fork 13.2k
Type inference in conditional types#21496
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
Uh oh!
There was an error while loading. Please reload this page.
Conversation
ahejlsberg commented Jan 30, 2018 • edited
Loading Uh oh!
There was an error while loading. Please reload this page.
edited
Uh oh!
There was an error while loading. Please reload this page.
# Conflicts: # src/compiler/checker.ts
# Conflicts: # src/compiler/checker.ts # src/compiler/types.ts # tests/baselines/reference/api/tsserverlibrary.d.ts # tests/baselines/reference/api/typescript.d.ts
MadaraUchiha commented Feb 8, 2018
@simonbuchan You don't need declarefunctionzip<A,B>(a: ReadonlyArray<A>,b: ReadonlyArray<B>): Array<[A,B]>;You really only need infer when A is part of another type you don't particularly know about, for example, you have |
simonbuchan commented Feb 8, 2018
The issue is more about how you would describe Basically: Here's another case, where the user is trying to emulate the flow // Must be a promise, but I can't be bothered writing what kindletfoo: Promise<infer T>=asyncMethod(); |
benstevens48 commented Feb 10, 2018
I actually suggested this more general use of |
masaeedu commented Feb 11, 2018
KiaraGrouwstra commented Feb 11, 2018
@jcalz: I can't tell what JS function you're typing there, but now that typeEverything={foo: (x: {a: string;})=>void;bar: (x: {b: number;})=>void;baz: (x: {c: boolean;})=>void;}.. so apparently these |
jcalz commented Feb 11, 2018
@tycho01 Hmm, I just checked 2.8.0-dev.20180211 and it gives: typeEverything={a: string;}&{b: number;}&{c: boolean;}which is indeed the intersection type I was aiming for. Not sure why you see something else. |
MeirionHughes commented Feb 13, 2018 • edited
Loading Uh oh!
There was an error while loading. Please reload this page.
edited
Uh oh!
There was an error while loading. Please reload this page.
|
masaeedu commented Feb 13, 2018 • edited
Loading Uh oh!
There was an error while loading. Please reload this page.
edited
Uh oh!
There was an error while loading. Please reload this page.
@MeirionHughes |
MeirionHughes commented Feb 13, 2018 • edited
Loading Uh oh!
There was an error while loading. Please reload this page.
edited
Uh oh!
There was an error while loading. Please reload this page.
@masaeedu Yeah, my apologies - I was confusing this one with 21316. |
ericanderson commented Feb 14, 2018
Any updates on recursively handling this? |
KiaraGrouwstra commented Feb 14, 2018
MeirionHughes commented Feb 18, 2018 • edited
Loading Uh oh!
There was an error while loading. Please reload this page.
edited
Uh oh!
There was an error while loading. Please reload this page.
I'm trying to do a promisify and it seems to die if you give it an overloaded method. The single case works perfectly fine: typePromisify<T>=Textends(cb: (v: infer V)=>void)=>void ? ()=>Promise<V> : Textends(a: infer A,cb: (v: infer V)=>void)=>void ? (a: A)=>Promise<V> : Textends(a: infer A,b: infer B,cb: (v: infer V)=>void)=>void ? (a: A,b: B)=>Promise<V> : T;typeFoo=((a: string,cb: (v)=>void)=>void)letbar: Promisify<Foo>;overload it and it dies completely: typeFoo=((a: string,cb: (v)=>void)=>void)&((a: string,b: number,cb: (v)=>void)=>void);
never mind - its mentioned it isn't supported - still, it shows nothing (first post says it should be picking the last signature). So maybe it is a bug? |
MeirionHughes commented Feb 23, 2018 • edited
Loading Uh oh!
There was an error while loading. Please reload this page.
edited
Uh oh!
There was an error while loading. Please reload this page.
@ahejlsberg this limitation on the function overloads is super annoying (not to sound ungrateful: this pr is awesome) - I can't seem to find a way to "mask" the input function (pick from the overloads) either. You mention you choose the last function from the available ones. Would it not be possible to try each until you arrive at a non- |
Although (infer T) must frequently be parenthesized to avoid ambiguity, Recast does not have to encode that logic into FastPath#needsParens, because Babylon wraps such types with TSParenthesizedType. Cool! babel/babel#7404benjamn/ast-types@da0367bmicrosoft/TypeScript#21316microsoft/TypeScript#21496
donaldpipowitch commented May 16, 2018
As |

This PR introduces the ability to use type inference in conditional types (#21316), enabling pattern matching for types. For example, the following extracts the return type of a function type:
Within the
extendsclause of a conditional type, it is now possible to haveinferdeclarations that introduce a type variable to be inferred. Such inferred type variables may be referenced in the true branch of the conditional type. It is possible to have multipleinferlocations for the same type variable.A conditional type
T extends U ? X : Yis either resolved toXorY, or deferred because the condition depends on one or more type variables. Whether to resolve or defer is determined as follows:T'andU'that are instantiations ofTandUwhere all occurrences of type parameters are replaced withany, ifT'is not assignable toU', the conditional type is resolved toY. Intuitively, if the most permissive instantiation ofTis not assignable to the most permissive instantiation ofU, we know that no instantiation will be and we can just resolve toY.inferdeclaration withinUcollect a set of candidate types by inferring fromTtoU(using the same inference algorithm as type inference for generic functions). For a giveninfertype variableV, if any candidates were inferred from co-variant positions, the type inferred forVis a union of those candidates. Otherwise, if any candidates were inferred from contra-variant positions, the type inferred forVis an intersection of those candidates. Otherwise, the type inferred forVisnever.T''that is an instantiation ofTwhere allinfertype variables are replaced with the types inferred in the previous step, ifT''is definitely assignable toU, the conditional type is resolved toX. The definitely assignable relation is the same as the regular assignable relation, except that type variable constraints are not considered. Intuitively, when a type is definitely assignable to another type, we know that it will be assignable for all instantiations of those types.Conditional types can be nested to form a sequence of pattern matches that are evaluated in order:
Note that is not possible for a conditional type to recursively reference itself, as might be desired in the
Unpacked<T>case above. We're still considering ways in which to implement this.The following example demonstrates how multiple candidates for the same type variable in co-variant positions causes a union type to be inferred:
Likewise, multiple candidates for the same type variable in contra-variant positions causes an intersection type to be inferred:
When inferring from a type with multiple call signatures (such as the type of an overloaded function), inferences are made from the last signature (which, presumably, is the most permissive catch-all case). It is not possible to perform overload resolution based on a list of argument types (this would require us to support
typeoffor arbitrary expressions, as suggested in #6606, or something similar).It is not possible to use
inferdeclarations in constraint clauses for regular type parameters:However, much the same effect can be obtained by erasing the type variables in the constraint and instead specifying a conditional type: