restore any narrowing

This commit is contained in:
Wesley Wigham 2015-10-28 16:29:36 -07:00
parent febda00f1b
commit 168c664639
4 changed files with 57 additions and 160 deletions

View file

@ -6356,9 +6356,6 @@ namespace ts {
return type;
function narrowTypeByEquality(type: Type, expr: BinaryExpression, assumeTrue: boolean): Type {
if (!(type.flags & TypeFlags.Union)) {
return type;
}
// Check that we have 'typeof <symbol>' on the left and string literal on the right
if (expr.left.kind !== SyntaxKind.TypeOfExpression || expr.right.kind !== SyntaxKind.StringLiteral) {
return type;
@ -6372,6 +6369,14 @@ namespace ts {
assumeTrue = !assumeTrue;
}
let typeInfo = primitiveTypeInfo[right.text];
// If the type to be narrowed is any and we're affirmatively checking against a primitive, return the primitive
if (!!(type.flags & TypeFlags.Any) && typeInfo && assumeTrue) {
return typeInfo.type;
}
// At this point we can bail if it's not a union
if (!(type.flags & TypeFlags.Union)) {
return type;
}
let flags = typeInfo ? typeInfo.flags : (assumeTrue = !assumeTrue, TypeFlags.NumberLike | TypeFlags.StringLike | TypeFlags.ESSymbol | TypeFlags.Boolean);
let union = type as UnionType;
if (assumeTrue) {

View file

@ -0,0 +1,49 @@
tests/cases/conformance/expressions/typeGuards/typeGuardsWithAny.ts(11,7): error TS2339: Property 'p' does not exist on type 'string'.
tests/cases/conformance/expressions/typeGuards/typeGuardsWithAny.ts(18,7): error TS2339: Property 'p' does not exist on type 'number'.
tests/cases/conformance/expressions/typeGuards/typeGuardsWithAny.ts(25,7): error TS2339: Property 'p' does not exist on type 'boolean'.
==== tests/cases/conformance/expressions/typeGuards/typeGuardsWithAny.ts (3 errors) ====
var x: any = { p: 0 };
if (x instanceof Object) {
x.p; // No error, type any unaffected by instanceof type guard
}
else {
x.p; // No error, type any unaffected by instanceof type guard
}
if (typeof x === "string") {
x.p; // Error, type any narrowed by primitive type check
~
!!! error TS2339: Property 'p' does not exist on type 'string'.
}
else {
x.p; // No error, type unaffected in this branch
}
if (typeof x === "number") {
x.p; // Error, type any narrowed by primitive type check
~
!!! error TS2339: Property 'p' does not exist on type 'number'.
}
else {
x.p; // No error, type unaffected in this branch
}
if (typeof x === "boolean") {
x.p; // Error, type any narrowed by primitive type check
~
!!! error TS2339: Property 'p' does not exist on type 'boolean'.
}
else {
x.p; // No error, type unaffected in this branch
}
if (typeof x === "object") {
x.p; // No error, type any only affected by primitive type check
}
else {
x.p; // No error, type unaffected in this branch
}

View file

@ -1,61 +0,0 @@
=== tests/cases/conformance/expressions/typeGuards/typeGuardsWithAny.ts ===
var x: any = { p: 0 };
>x : Symbol(x, Decl(typeGuardsWithAny.ts, 0, 3))
>p : Symbol(p, Decl(typeGuardsWithAny.ts, 0, 14))
if (x instanceof Object) {
>x : Symbol(x, Decl(typeGuardsWithAny.ts, 0, 3))
>Object : Symbol(Object, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
x.p; // No error, type any unaffected by instanceof type guard
>x : Symbol(x, Decl(typeGuardsWithAny.ts, 0, 3))
}
else {
x.p; // No error, type any unaffected by instanceof type guard
>x : Symbol(x, Decl(typeGuardsWithAny.ts, 0, 3))
}
if (typeof x === "string") {
>x : Symbol(x, Decl(typeGuardsWithAny.ts, 0, 3))
x.p; // Error, type any narrowed by primitive type check
>x : Symbol(x, Decl(typeGuardsWithAny.ts, 0, 3))
}
else {
x.p; // No error, type unaffected in this branch
>x : Symbol(x, Decl(typeGuardsWithAny.ts, 0, 3))
}
if (typeof x === "number") {
>x : Symbol(x, Decl(typeGuardsWithAny.ts, 0, 3))
x.p; // Error, type any narrowed by primitive type check
>x : Symbol(x, Decl(typeGuardsWithAny.ts, 0, 3))
}
else {
x.p; // No error, type unaffected in this branch
>x : Symbol(x, Decl(typeGuardsWithAny.ts, 0, 3))
}
if (typeof x === "boolean") {
>x : Symbol(x, Decl(typeGuardsWithAny.ts, 0, 3))
x.p; // Error, type any narrowed by primitive type check
>x : Symbol(x, Decl(typeGuardsWithAny.ts, 0, 3))
}
else {
x.p; // No error, type unaffected in this branch
>x : Symbol(x, Decl(typeGuardsWithAny.ts, 0, 3))
}
if (typeof x === "object") {
>x : Symbol(x, Decl(typeGuardsWithAny.ts, 0, 3))
x.p; // No error, type any only affected by primitive type check
>x : Symbol(x, Decl(typeGuardsWithAny.ts, 0, 3))
}
else {
x.p; // No error, type unaffected in this branch
>x : Symbol(x, Decl(typeGuardsWithAny.ts, 0, 3))
}

View file

@ -1,96 +0,0 @@
=== tests/cases/conformance/expressions/typeGuards/typeGuardsWithAny.ts ===
var x: any = { p: 0 };
>x : any
>{ p: 0 } : { p: number; }
>p : number
>0 : number
if (x instanceof Object) {
>x instanceof Object : boolean
>x : any
>Object : ObjectConstructor
x.p; // No error, type any unaffected by instanceof type guard
>x.p : any
>x : any
>p : any
}
else {
x.p; // No error, type any unaffected by instanceof type guard
>x.p : any
>x : any
>p : any
}
if (typeof x === "string") {
>typeof x === "string" : boolean
>typeof x : string
>x : any
>"string" : string
x.p; // Error, type any narrowed by primitive type check
>x.p : any
>x : any
>p : any
}
else {
x.p; // No error, type unaffected in this branch
>x.p : any
>x : any
>p : any
}
if (typeof x === "number") {
>typeof x === "number" : boolean
>typeof x : string
>x : any
>"number" : string
x.p; // Error, type any narrowed by primitive type check
>x.p : any
>x : any
>p : any
}
else {
x.p; // No error, type unaffected in this branch
>x.p : any
>x : any
>p : any
}
if (typeof x === "boolean") {
>typeof x === "boolean" : boolean
>typeof x : string
>x : any
>"boolean" : string
x.p; // Error, type any narrowed by primitive type check
>x.p : any
>x : any
>p : any
}
else {
x.p; // No error, type unaffected in this branch
>x.p : any
>x : any
>p : any
}
if (typeof x === "object") {
>typeof x === "object" : boolean
>typeof x : string
>x : any
>"object" : string
x.p; // No error, type any only affected by primitive type check
>x.p : any
>x : any
>p : any
}
else {
x.p; // No error, type unaffected in this branch
>x.p : any
>x : any
>p : any
}