Merge pull request #6330 from weswigham/restorative-narrowing

Fix #6277
This commit is contained in:
Daniel Rosenwasser 2016-01-14 16:07:59 -08:00
commit 403a93d21f
5 changed files with 192 additions and 4 deletions

View File

@ -6722,10 +6722,6 @@ namespace ts {
if (typeInfo && typeInfo.type === undefinedType) {
return type;
}
// If the type to be narrowed is any and we're checking a primitive with assumeTrue=true, return the primitive
if (!!(type.flags & TypeFlags.Any) && typeInfo && assumeTrue) {
return typeInfo.type;
}
let flags: TypeFlags;
if (typeInfo) {
flags = typeInfo.flags;
@ -6736,6 +6732,10 @@ namespace ts {
}
// At this point we can bail if it's not a union
if (!(type.flags & TypeFlags.Union)) {
// If we're on the true branch and the type is a subtype, we should return the primitive type
if (assumeTrue && typeInfo && isTypeSubtypeOf(typeInfo.type, type)) {
return typeInfo.type;
}
// If the active non-union type would be removed from a union by this type guard, return an empty union
return filterUnion(type) ? type : emptyUnionType;
}

View File

@ -0,0 +1,45 @@
//// [typeGuardOfFormTypeOfPrimitiveSubtype.ts]
let a: {};
let b: {toString(): string};
if (typeof a === "number") {
let c: number = a;
}
if (typeof a === "string") {
let c: string = a;
}
if (typeof a === "boolean") {
let c: boolean = a;
}
if (typeof b === "number") {
let c: number = b;
}
if (typeof b === "string") {
let c: string = b;
}
if (typeof b === "boolean") {
let c: boolean = b;
}
//// [typeGuardOfFormTypeOfPrimitiveSubtype.js]
var a;
var b;
if (typeof a === "number") {
var c = a;
}
if (typeof a === "string") {
var c = a;
}
if (typeof a === "boolean") {
var c = a;
}
if (typeof b === "number") {
var c = b;
}
if (typeof b === "string") {
var c = b;
}
if (typeof b === "boolean") {
var c = b;
}

View File

@ -0,0 +1,52 @@
=== tests/cases/conformance/expressions/typeGuards/typeGuardOfFormTypeOfPrimitiveSubtype.ts ===
let a: {};
>a : Symbol(a, Decl(typeGuardOfFormTypeOfPrimitiveSubtype.ts, 0, 3))
let b: {toString(): string};
>b : Symbol(b, Decl(typeGuardOfFormTypeOfPrimitiveSubtype.ts, 1, 3))
>toString : Symbol(toString, Decl(typeGuardOfFormTypeOfPrimitiveSubtype.ts, 1, 8))
if (typeof a === "number") {
>a : Symbol(a, Decl(typeGuardOfFormTypeOfPrimitiveSubtype.ts, 0, 3))
let c: number = a;
>c : Symbol(c, Decl(typeGuardOfFormTypeOfPrimitiveSubtype.ts, 3, 7))
>a : Symbol(a, Decl(typeGuardOfFormTypeOfPrimitiveSubtype.ts, 0, 3))
}
if (typeof a === "string") {
>a : Symbol(a, Decl(typeGuardOfFormTypeOfPrimitiveSubtype.ts, 0, 3))
let c: string = a;
>c : Symbol(c, Decl(typeGuardOfFormTypeOfPrimitiveSubtype.ts, 6, 7))
>a : Symbol(a, Decl(typeGuardOfFormTypeOfPrimitiveSubtype.ts, 0, 3))
}
if (typeof a === "boolean") {
>a : Symbol(a, Decl(typeGuardOfFormTypeOfPrimitiveSubtype.ts, 0, 3))
let c: boolean = a;
>c : Symbol(c, Decl(typeGuardOfFormTypeOfPrimitiveSubtype.ts, 9, 7))
>a : Symbol(a, Decl(typeGuardOfFormTypeOfPrimitiveSubtype.ts, 0, 3))
}
if (typeof b === "number") {
>b : Symbol(b, Decl(typeGuardOfFormTypeOfPrimitiveSubtype.ts, 1, 3))
let c: number = b;
>c : Symbol(c, Decl(typeGuardOfFormTypeOfPrimitiveSubtype.ts, 13, 7))
>b : Symbol(b, Decl(typeGuardOfFormTypeOfPrimitiveSubtype.ts, 1, 3))
}
if (typeof b === "string") {
>b : Symbol(b, Decl(typeGuardOfFormTypeOfPrimitiveSubtype.ts, 1, 3))
let c: string = b;
>c : Symbol(c, Decl(typeGuardOfFormTypeOfPrimitiveSubtype.ts, 16, 7))
>b : Symbol(b, Decl(typeGuardOfFormTypeOfPrimitiveSubtype.ts, 1, 3))
}
if (typeof b === "boolean") {
>b : Symbol(b, Decl(typeGuardOfFormTypeOfPrimitiveSubtype.ts, 1, 3))
let c: boolean = b;
>c : Symbol(c, Decl(typeGuardOfFormTypeOfPrimitiveSubtype.ts, 19, 7))
>b : Symbol(b, Decl(typeGuardOfFormTypeOfPrimitiveSubtype.ts, 1, 3))
}

View File

@ -0,0 +1,70 @@
=== tests/cases/conformance/expressions/typeGuards/typeGuardOfFormTypeOfPrimitiveSubtype.ts ===
let a: {};
>a : {}
let b: {toString(): string};
>b : { toString(): string; }
>toString : () => string
if (typeof a === "number") {
>typeof a === "number" : boolean
>typeof a : string
>a : {}
>"number" : string
let c: number = a;
>c : number
>a : number
}
if (typeof a === "string") {
>typeof a === "string" : boolean
>typeof a : string
>a : {}
>"string" : string
let c: string = a;
>c : string
>a : string
}
if (typeof a === "boolean") {
>typeof a === "boolean" : boolean
>typeof a : string
>a : {}
>"boolean" : string
let c: boolean = a;
>c : boolean
>a : boolean
}
if (typeof b === "number") {
>typeof b === "number" : boolean
>typeof b : string
>b : { toString(): string; }
>"number" : string
let c: number = b;
>c : number
>b : number
}
if (typeof b === "string") {
>typeof b === "string" : boolean
>typeof b : string
>b : { toString(): string; }
>"string" : string
let c: string = b;
>c : string
>b : string
}
if (typeof b === "boolean") {
>typeof b === "boolean" : boolean
>typeof b : string
>b : { toString(): string; }
>"boolean" : string
let c: boolean = b;
>c : boolean
>b : boolean
}

View File

@ -0,0 +1,21 @@
let a: {};
let b: {toString(): string};
if (typeof a === "number") {
let c: number = a;
}
if (typeof a === "string") {
let c: string = a;
}
if (typeof a === "boolean") {
let c: boolean = a;
}
if (typeof b === "number") {
let c: number = b;
}
if (typeof b === "string") {
let c: string = b;
}
if (typeof b === "boolean") {
let c: boolean = b;
}