Improved handing of union types in type guards

This commit is contained in:
Anders Hejlsberg 2015-01-12 14:51:20 -08:00
parent bf46e50f89
commit 59e266de02
6 changed files with 73 additions and 7 deletions

View file

@ -4709,13 +4709,21 @@ module ts {
if (!isTypeSubtypeOf(rightType, globalFunctionType)) {
return type;
}
// Target type is type of prototype property
var prototypeProperty = getPropertyOfType(rightType, "prototype");
if (!prototypeProperty) {
return type;
}
var prototypeType = getTypeOfSymbol(prototypeProperty);
// Narrow to type of prototype property if it is a subtype of current type
return isTypeSubtypeOf(prototypeType, type) ? prototypeType : type;
var targetType = getTypeOfSymbol(prototypeProperty);
// Narrow to target type if it is a subtype of current type
if (isTypeSubtypeOf(targetType, type)) {
return targetType;
}
// If current type is a union type, remove all constituents that aren't subtypes of target type
if (type.flags && TypeFlags.Union) {
return getUnionType(filter((<UnionType>type).types, t => isTypeSubtypeOf(t, targetType)));
}
return type;
}
// Narrow the given type based on the given expression having the assumed boolean value

View file

@ -0,0 +1,23 @@
//// [TypeGuardWithArrayUnion.ts]
class Message {
value: string;
}
function saySize(message: Message | Message[]) {
if (message instanceof Array) {
return message.length; // Should have type Message[] here
}
}
//// [TypeGuardWithArrayUnion.js]
var Message = (function () {
function Message() {
}
return Message;
})();
function saySize(message) {
if (message instanceof Array) {
return message.length; // Should have type Message[] here
}
}

View file

@ -0,0 +1,26 @@
=== tests/cases/conformance/expressions/typeGuards/TypeGuardWithArrayUnion.ts ===
class Message {
>Message : Message
value: string;
>value : string
}
function saySize(message: Message | Message[]) {
>saySize : (message: Message | Message[]) => number
>message : Message | Message[]
>Message : Message
>Message : Message
if (message instanceof Array) {
>message instanceof Array : boolean
>message : Message | Message[]
>Array : ArrayConstructor
return message.length; // Should have type Message[] here
>message.length : number
>message : Message[]
>length : number
}
}

View file

@ -124,9 +124,9 @@ var r2: D1 | C2 = c2Ord1 instanceof C1 && c2Ord1; // C2 | D1
>r2 : C2 | D1
>D1 : D1
>C2 : C2
>c2Ord1 instanceof C1 && c2Ord1 : C2 | D1
>c2Ord1 instanceof C1 && c2Ord1 : D1
>c2Ord1 instanceof C1 : boolean
>c2Ord1 : C2 | D1
>C1 : typeof C1
>c2Ord1 : C2 | D1
>c2Ord1 : D1

View file

@ -154,9 +154,9 @@ var r2: D1 | C2 = c2Ord1 instanceof c1 && c2Ord1; // C2 | D1
>r2 : C2 | D1
>D1 : D1
>C2 : C2
>c2Ord1 instanceof c1 && c2Ord1 : C2 | D1
>c2Ord1 instanceof c1 && c2Ord1 : D1
>c2Ord1 instanceof c1 : boolean
>c2Ord1 : C2 | D1
>c1 : C1
>c2Ord1 : C2 | D1
>c2Ord1 : D1

View file

@ -0,0 +1,9 @@
class Message {
value: string;
}
function saySize(message: Message | Message[]) {
if (message instanceof Array) {
return message.length; // Should have type Message[] here
}
}