Skip to content

Commit cbecae3

Browse files
committed
Merge pull request #1657 from Microsoft/unionTypeGuards
Improved union type guards
2 parents 8256ddf + 59e266d commit cbecae3

File tree

6 files changed

+73
-7
lines changed

6 files changed

+73
-7
lines changed

src/compiler/checker.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4709,13 +4709,21 @@ module ts {
47094709
if (!isTypeSubtypeOf(rightType, globalFunctionType)) {
47104710
return type;
47114711
}
4712+
// Target type is type of prototype property
47124713
var prototypeProperty = getPropertyOfType(rightType, "prototype");
47134714
if (!prototypeProperty) {
47144715
return type;
47154716
}
4716-
var prototypeType = getTypeOfSymbol(prototypeProperty);
4717-
// Narrow to type of prototype property if it is a subtype of current type
4718-
return isTypeSubtypeOf(prototypeType, type) ? prototypeType : type;
4717+
var targetType = getTypeOfSymbol(prototypeProperty);
4718+
// Narrow to target type if it is a subtype of current type
4719+
if (isTypeSubtypeOf(targetType, type)) {
4720+
return targetType;
4721+
}
4722+
// If current type is a union type, remove all constituents that aren't subtypes of target type
4723+
if (type.flags && TypeFlags.Union) {
4724+
return getUnionType(filter((<UnionType>type).types, t => isTypeSubtypeOf(t, targetType)));
4725+
}
4726+
return type;
47194727
}
47204728

47214729
// Narrow the given type based on the given expression having the assumed boolean value
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
//// [TypeGuardWithArrayUnion.ts]
2+
class Message {
3+
value: string;
4+
}
5+
6+
function saySize(message: Message | Message[]) {
7+
if (message instanceof Array) {
8+
return message.length; // Should have type Message[] here
9+
}
10+
}
11+
12+
13+
//// [TypeGuardWithArrayUnion.js]
14+
var Message = (function () {
15+
function Message() {
16+
}
17+
return Message;
18+
})();
19+
function saySize(message) {
20+
if (message instanceof Array) {
21+
return message.length; // Should have type Message[] here
22+
}
23+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
=== tests/cases/conformance/expressions/typeGuards/TypeGuardWithArrayUnion.ts ===
2+
class Message {
3+
>Message : Message
4+
5+
value: string;
6+
>value : string
7+
}
8+
9+
function saySize(message: Message | Message[]) {
10+
>saySize : (message: Message | Message[]) => number
11+
>message : Message | Message[]
12+
>Message : Message
13+
>Message : Message
14+
15+
if (message instanceof Array) {
16+
>message instanceof Array : boolean
17+
>message : Message | Message[]
18+
>Array : ArrayConstructor
19+
20+
return message.length; // Should have type Message[] here
21+
>message.length : number
22+
>message : Message[]
23+
>length : number
24+
}
25+
}
26+

tests/baselines/reference/typeGuardOfFormInstanceOf.types

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -124,9 +124,9 @@ var r2: D1 | C2 = c2Ord1 instanceof C1 && c2Ord1; // C2 | D1
124124
>r2 : C2 | D1
125125
>D1 : D1
126126
>C2 : C2
127-
>c2Ord1 instanceof C1 && c2Ord1 : C2 | D1
127+
>c2Ord1 instanceof C1 && c2Ord1 : D1
128128
>c2Ord1 instanceof C1 : boolean
129129
>c2Ord1 : C2 | D1
130130
>C1 : typeof C1
131-
>c2Ord1 : C2 | D1
131+
>c2Ord1 : D1
132132

tests/baselines/reference/typeGuardOfFormInstanceOfOnInterface.types

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -154,9 +154,9 @@ var r2: D1 | C2 = c2Ord1 instanceof c1 && c2Ord1; // C2 | D1
154154
>r2 : C2 | D1
155155
>D1 : D1
156156
>C2 : C2
157-
>c2Ord1 instanceof c1 && c2Ord1 : C2 | D1
157+
>c2Ord1 instanceof c1 && c2Ord1 : D1
158158
>c2Ord1 instanceof c1 : boolean
159159
>c2Ord1 : C2 | D1
160160
>c1 : C1
161-
>c2Ord1 : C2 | D1
161+
>c2Ord1 : D1
162162

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
class Message {
2+
value: string;
3+
}
4+
5+
function saySize(message: Message | Message[]) {
6+
if (message instanceof Array) {
7+
return message.length; // Should have type Message[] here
8+
}
9+
}

0 commit comments

Comments
 (0)