You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Unions and intersections of type predicates produce wrong type #17757
changed the title [-]Unions of type predicates types produce wrong type[/-][+]Unions and intersections of type predicates types produce wrong type[/+]on Aug 12, 2017
changed the title [-]Unions and intersections of type predicates types produce wrong type[/-][+]Unions and intersections of type predicates produce wrong type[/+]on Aug 12, 2017
I was thinking of this more as a bug report than a feature request, but if we're doing demonstrations of value, this was my scenario.
The typescript compiler has lots of Node types differentiated by a kind enum property, but no discriminated union type exists to allow nicely switching on kinds. The compiler itself does lots of ugly and dangerous asserting to get around this. There are, however, ts.isWhileStatement(node: Node) style functions for almost all nodes.
I was trying to put together something like this:
functionisAnyOf<Textendsts.Node>(node: ts.Node, ...preds: Array<(n: ts.Node)=>n is T>): node is T{returnpreds.some(p=>p(node));}if(isAnyOf(node,ts.isWhileStatement,ts.isIfStatement)){// node should have type ts.WhileStatement | ts.IfStatement// actually just has type ts.WhileStatement}
But with the current behaviour/bug, T just takes the type of whatever the first predicate is and completely ignores the others.
Ryan Cavanaugh (@RyanCavanaugh) I'm interested in tackling this issue, can you point me towards what changes will be needed? I was able to find (and fix) an issue where Type Predicates weren't being correctly handled by getContextualSignature in checker.ts, however that didn't seem to change the behavior at all. It seems that getContextualSignature isn't actually used inside of resolveCall so the Type Predicate still isn't being correctly determined.
Andy (Andrewkraft) (@Andy-MS) Thanks, I'll take a look at the intersection part. I actually had just figured out what I was missing, but I'm glad to see I came up with essentially the same solution as you for the union signatures.
I think this issue can be closed. The union case correctly works by selecting both predicate types:
typeIsStringOrNumber=((x: any)=>x is number)|((x: any)=>x is string);declareconstx: any;if((((x: any)=>true)asIsStringOrNumber)(x)){x.toFixed();// x has type number | string}
The intersection case still selects the first overload, but this is a general problem with intersections of signatures---it is not a particular issue with type predicates.
Activity
aluanhaddad commentedon Aug 12, 2017
It appears to just grab the first type predicate and ignore the rest.
Here is a self-contained repro (2.5.0-dev.20170808)
Intersecting type predicates seems to have the same result, only the first signature is considered.
[-]Unions of type guard types produce wrong type[/-][+]Unions of type predicates types produce wrong type[/+]SamPruden commentedon Aug 12, 2017
I knew using "type guards" like that wasn't quite right. 😂
[-]Unions of type predicates types produce wrong type[/-][+]Unions and intersections of type predicates types produce wrong type[/+][-]Unions and intersections of type predicates types produce wrong type[/-][+]Unions and intersections of type predicates produce wrong type[/+]aluanhaddad commentedon Aug 13, 2017
Being able to compose these functions would be highly useful.
Imagine a rather heterogeneous array elements of elements in a scenario such as
There is some boilerplate in the example, but throw in a
composehelper and it would make for some very nice patterns.SamPruden commentedon Aug 13, 2017
I was thinking of this more as a bug report than a feature request, but if we're doing demonstrations of value, this was my scenario.
The typescript compiler has lots of
Nodetypes differentiated by akindenum property, but no discriminated union type exists to allow nicely switching on kinds. The compiler itself does lots of ugly and dangerous asserting to get around this. There are, however,ts.isWhileStatement(node: Node)style functions for almost all nodes.I was trying to put together something like this:
But with the current behaviour/bug,
Tjust takes the type of whatever the first predicate is and completely ignores the others.RyanCavanaugh commentedon Aug 16, 2017
Probably an easy fix if someone wants to try
charlespierce commentedon Oct 6, 2017
Ryan Cavanaugh (@RyanCavanaugh) I'm interested in tackling this issue, can you point me towards what changes will be needed? I was able to find (and fix) an issue where Type Predicates weren't being correctly handled by
getContextualSignatureinchecker.ts, however that didn't seem to change the behavior at all. It seems thatgetContextualSignatureisn't actually used inside ofresolveCallso the Type Predicate still isn't being correctly determined.charlespierce commentedon Oct 6, 2017
Andy (Andrewkraft) (@Andy-MS) Thanks, I'll take a look at the intersection part. I actually had just figured out what I was missing, but I'm glad to see I came up with essentially the same solution as you for the union signatures.
jack-williams commentedon Feb 10, 2019
I think this issue can be closed. The union case correctly works by selecting both predicate types:
The intersection case still selects the first overload, but this is a general problem with intersections of signatures---it is not a particular issue with type predicates.