From 069f73d0f20e2b8957fa7671c06a0a16160c71a8 Mon Sep 17 00:00:00 2001 From: IdeaHunter Date: Fri, 21 Apr 2017 02:03:25 +0300 Subject: [PATCH] Change type narrowing for optional properties --- src/compiler/checker.ts | 22 +- .../reference/inKeywordTypeguard.errors.txt | 29 ++- .../baselines/reference/inKeywordTypeguard.js | 44 ++-- .../typeGuardOfFromPropNameInUnionType.js | 72 +++-- ...typeGuardOfFromPropNameInUnionType.symbols | 245 ++++++++++-------- .../typeGuardOfFromPropNameInUnionType.types | 107 +++++--- tests/cases/compiler/inKeywordTypeguard.ts | 192 +++++++------- .../typeGuardOfFromPropNameInUnionType.ts | 166 ++++++------ 8 files changed, 517 insertions(+), 360 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 1fc35e174d..7f2db45bab 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -12722,10 +12722,30 @@ namespace ts { return type; } + function isTypePresencePossible(type: Type, propName: string, shouldHaveProperty: boolean) { + const prop = getPropertyOfType(type, propName); + if (!prop) { + // if there is NO property: + // - but we assume type SHOULD have it then presence of object of following type IS NOT possible + // - and we assume type SHOULD NOT have it then presence of object of following type IS possible + return !shouldHaveProperty; + } else if (prop.flags & SymbolFlags.Optional) { + // if there is an optional property: + // - and we assume type SHOULD have it then presence of object of following type IS possible + // - but assume type SHOULD NOT have it then presence of object of following type IS still possible + return true; + } else /* if (prop.flags & SymbolFlags.Required) */ { + // if there is a required property: + // - and we assume type SHOULD have it then presence of object of following type IS possible + // - but we assume type SHOULD NOT have it then presence of object of following type IS NOT possible + return shouldHaveProperty; + } + } + function narrowByInKeyword(type: Type, literal: LiteralExpression, assumeTrue: boolean) { if ((type.flags & (TypeFlags.Union | TypeFlags.Object)) || (type.flags & TypeFlags.TypeParameter && (type as TypeParameter).isThisType)) { const propName = literal.text; - return filterType(type, t => !!getPropertyOfType(t, propName) === assumeTrue); + return filterType(type, t => isTypePresencePossible(t, propName, /* shouldHaveProperty */ assumeTrue)); } return type; } diff --git a/tests/baselines/reference/inKeywordTypeguard.errors.txt b/tests/baselines/reference/inKeywordTypeguard.errors.txt index 4ee09e71b6..914daf42a7 100644 --- a/tests/baselines/reference/inKeywordTypeguard.errors.txt +++ b/tests/baselines/reference/inKeywordTypeguard.errors.txt @@ -2,6 +2,8 @@ tests/cases/compiler/inKeywordTypeguard.ts(6,11): error TS2339: Property 'b' doe tests/cases/compiler/inKeywordTypeguard.ts(8,11): error TS2339: Property 'a' does not exist on type 'B'. tests/cases/compiler/inKeywordTypeguard.ts(14,11): error TS2339: Property 'b' does not exist on type 'A'. tests/cases/compiler/inKeywordTypeguard.ts(16,11): error TS2339: Property 'a' does not exist on type 'B'. +tests/cases/compiler/inKeywordTypeguard.ts(27,11): error TS2339: Property 'b' does not exist on type 'AWithOptionalProp | BWithOptionalProp'. + Property 'b' does not exist on type 'AWithOptionalProp'. tests/cases/compiler/inKeywordTypeguard.ts(42,11): error TS2339: Property 'b' does not exist on type 'AWithMethod'. tests/cases/compiler/inKeywordTypeguard.ts(49,11): error TS2339: Property 'a' does not exist on type 'never'. tests/cases/compiler/inKeywordTypeguard.ts(50,11): error TS2339: Property 'b' does not exist on type 'never'. @@ -19,7 +21,7 @@ tests/cases/compiler/inKeywordTypeguard.ts(84,39): error TS2339: Property 'a' do tests/cases/compiler/inKeywordTypeguard.ts(94,26): error TS2339: Property 'a' does not exist on type 'never'. -==== tests/cases/compiler/inKeywordTypeguard.ts (16 errors) ==== +==== tests/cases/compiler/inKeywordTypeguard.ts (17 errors) ==== class A { a: string; } class B { b: string; } @@ -47,23 +49,26 @@ tests/cases/compiler/inKeywordTypeguard.ts(94,26): error TS2339: Property 'a' do } } - class AOpt { a?: string } - class BOpn { b?: string } + class AWithOptionalProp { a?: string; } + class BWithOptionalProp { b?: string; } - function positiveTestClassesWithOptionalProperties(x: AOpt | BOpn) { + function positiveTestClassesWithOptionalProperties(x: AWithOptionalProp | BWithOptionalProp) { if ("a" in x) { x.a = "1"; } else { x.b = "1"; + ~ +!!! error TS2339: Property 'b' does not exist on type 'AWithOptionalProp | BWithOptionalProp'. +!!! error TS2339: Property 'b' does not exist on type 'AWithOptionalProp'. } } class AWithMethod { - a(): string { return "" } + a(): string { return ""; } } class BWithMethod { - b(): string { return "" } + b(): string { return ""; } } function negativeTestClassesWithMembers(x: AWithMethod | BWithMethod) { @@ -96,8 +101,8 @@ tests/cases/compiler/inKeywordTypeguard.ts(94,26): error TS2339: Property 'a' do } } - class C { a: string } - class D { a: string } + class C { a: string; } + class D { a: string; } function negativeMultipleClassesTest(x: A | B | C | D) { if ("a" in x) { @@ -112,9 +117,9 @@ tests/cases/compiler/inKeywordTypeguard.ts(94,26): error TS2339: Property 'a' do } } - class ClassWithProp { prop: A | B } + class ClassWithUnionProp { prop: A | B } - function negativePropTest(x: ClassWithProp) { + function negativePropTest(x: ClassWithUnionProp) { if ("a" in x.prop) { let y: string = x.prop.b; ~ @@ -129,7 +134,7 @@ tests/cases/compiler/inKeywordTypeguard.ts(94,26): error TS2339: Property 'a' do class NegativeClassTest { protected prop: A | B; inThis() { - if ('a' in this.prop) { + if ("a" in this.prop) { let z: number = this.prop.b; ~ !!! error TS2339: Property 'b' does not exist on type 'A'. @@ -144,7 +149,7 @@ tests/cases/compiler/inKeywordTypeguard.ts(94,26): error TS2339: Property 'a' do class UnreachableCodeDetection { a: string; inThis() { - if ('a' in this) { + if ("a" in this) { } else { let y = this.a; ~ diff --git a/tests/baselines/reference/inKeywordTypeguard.js b/tests/baselines/reference/inKeywordTypeguard.js index 33e8eefa14..643c73feb5 100644 --- a/tests/baselines/reference/inKeywordTypeguard.js +++ b/tests/baselines/reference/inKeywordTypeguard.js @@ -18,10 +18,10 @@ function positiveClassesTest(x: A | B) { } } -class AOpt { a?: string } -class BOpn { b?: string } +class AWithOptionalProp { a?: string; } +class BWithOptionalProp { b?: string; } -function positiveTestClassesWithOptionalProperties(x: AOpt | BOpn) { +function positiveTestClassesWithOptionalProperties(x: AWithOptionalProp | BWithOptionalProp) { if ("a" in x) { x.a = "1"; } else { @@ -30,11 +30,11 @@ function positiveTestClassesWithOptionalProperties(x: AOpt | BOpn) { } class AWithMethod { - a(): string { return "" } + a(): string { return ""; } } class BWithMethod { - b(): string { return "" } + b(): string { return ""; } } function negativeTestClassesWithMembers(x: AWithMethod | BWithMethod) { @@ -55,8 +55,8 @@ function negativeTestClassesWithMemberMissingInBothClasses(x: AWithMethod | BWit } } -class C { a: string } -class D { a: string } +class C { a: string; } +class D { a: string; } function negativeMultipleClassesTest(x: A | B | C | D) { if ("a" in x) { @@ -66,9 +66,9 @@ function negativeMultipleClassesTest(x: A | B | C | D) { } } -class ClassWithProp { prop: A | B } +class ClassWithUnionProp { prop: A | B } -function negativePropTest(x: ClassWithProp) { +function negativePropTest(x: ClassWithUnionProp) { if ("a" in x.prop) { let y: string = x.prop.b; } else { @@ -79,7 +79,7 @@ function negativePropTest(x: ClassWithProp) { class NegativeClassTest { protected prop: A | B; inThis() { - if ('a' in this.prop) { + if ("a" in this.prop) { let z: number = this.prop.b; } else { let y: string = this.prop.a; @@ -90,7 +90,7 @@ class NegativeClassTest { class UnreachableCodeDetection { a: string; inThis() { - if ('a' in this) { + if ("a" in this) { } else { let y = this.a; } @@ -124,15 +124,15 @@ function positiveClassesTest(x) { x.a = "1"; } } -var AOpt = (function () { - function AOpt() { +var AWithOptionalProp = (function () { + function AWithOptionalProp() { } - return AOpt; + return AWithOptionalProp; }()); -var BOpn = (function () { - function BOpn() { +var BWithOptionalProp = (function () { + function BWithOptionalProp() { } - return BOpn; + return BWithOptionalProp; }()); function positiveTestClassesWithOptionalProperties(x) { if ("a" in x) { @@ -190,10 +190,10 @@ function negativeMultipleClassesTest(x) { x.a = "1"; } } -var ClassWithProp = (function () { - function ClassWithProp() { +var ClassWithUnionProp = (function () { + function ClassWithUnionProp() { } - return ClassWithProp; + return ClassWithUnionProp; }()); function negativePropTest(x) { if ("a" in x.prop) { @@ -207,7 +207,7 @@ var NegativeClassTest = (function () { function NegativeClassTest() { } NegativeClassTest.prototype.inThis = function () { - if ('a' in this.prop) { + if ("a" in this.prop) { var z = this.prop.b; } else { @@ -220,7 +220,7 @@ var UnreachableCodeDetection = (function () { function UnreachableCodeDetection() { } UnreachableCodeDetection.prototype.inThis = function () { - if ('a' in this) { + if ("a" in this) { } else { var y = this.a; diff --git a/tests/baselines/reference/typeGuardOfFromPropNameInUnionType.js b/tests/baselines/reference/typeGuardOfFromPropNameInUnionType.js index 644abfaf33..76b10066fd 100644 --- a/tests/baselines/reference/typeGuardOfFromPropNameInUnionType.js +++ b/tests/baselines/reference/typeGuardOfFromPropNameInUnionType.js @@ -3,8 +3,6 @@ class A { a: string; } class B { b: number; } class C { b: Object; } class D { a: Date; } -class ClassWithProp { prop: A | B } -class NestedClassWithProp { outer: ClassWithProp } function namedClasses(x: A | B) { if ("a" in x) { @@ -29,6 +27,20 @@ function anonymousClasses(x: { a: string; } | { b: number; }) { let z: number = x.b; } } + +class AWithOptionalProp { a?: string; } +class BWithOptionalProp { b?: string; } + +function positiveTestClassesWithOptionalProperties(x: AWithOptionalProp | BWithOptionalProp) { + if ("a" in x) { + x.a = "1"; + } else { + const y: string = x instanceof AWithOptionalProp + ? x.a + : x.b + } +} + function inParenthesizedExpression(x: A | B) { if ("a" in (x)) { let y: string = x.a; @@ -37,8 +49,9 @@ function inParenthesizedExpression(x: A | B) { } } +class ClassWithUnionProp { prop: A | B; } -function inProperty(x: ClassWithProp) { +function inProperty(x: ClassWithUnionProp) { if ("a" in x.prop) { let y: string = x.prop.a; } else { @@ -46,6 +59,7 @@ function inProperty(x: ClassWithProp) { } } +class NestedClassWithProp { outer: ClassWithUnionProp; } function innestedProperty(x: NestedClassWithProp) { if ("a" in x.outer.prop) { @@ -58,7 +72,7 @@ function innestedProperty(x: NestedClassWithProp) { class InMemberOfClass { protected prop: A | B; inThis() { - if ('a' in this.prop) { + if ("a" in this.prop) { let y: string = this.prop.a; } else { let z: number = this.prop.b; @@ -66,11 +80,11 @@ class InMemberOfClass { } } -//added for completeness +// added for completeness class SelfAssert { a: string; inThis() { - if ('a' in this) { + if ("a" in this) { let y: string = this.a; } else { } @@ -98,16 +112,6 @@ var D = (function () { } return D; }()); -var ClassWithProp = (function () { - function ClassWithProp() { - } - return ClassWithProp; -}()); -var NestedClassWithProp = (function () { - function NestedClassWithProp() { - } - return NestedClassWithProp; -}()); function namedClasses(x) { if ("a" in x) { x.a = "1"; @@ -132,6 +136,26 @@ function anonymousClasses(x) { var z = x.b; } } +var AWithOptionalProp = (function () { + function AWithOptionalProp() { + } + return AWithOptionalProp; +}()); +var BWithOptionalProp = (function () { + function BWithOptionalProp() { + } + return BWithOptionalProp; +}()); +function positiveTestClassesWithOptionalProperties(x) { + if ("a" in x) { + x.a = "1"; + } + else { + var y = x instanceof AWithOptionalProp + ? x.a + : x.b; + } +} function inParenthesizedExpression(x) { if ("a" in (x)) { var y = x.a; @@ -140,6 +164,11 @@ function inParenthesizedExpression(x) { var z = x.b; } } +var ClassWithUnionProp = (function () { + function ClassWithUnionProp() { + } + return ClassWithUnionProp; +}()); function inProperty(x) { if ("a" in x.prop) { var y = x.prop.a; @@ -148,6 +177,11 @@ function inProperty(x) { var z = x.prop.b; } } +var NestedClassWithProp = (function () { + function NestedClassWithProp() { + } + return NestedClassWithProp; +}()); function innestedProperty(x) { if ("a" in x.outer.prop) { var y = x.outer.prop.a; @@ -160,7 +194,7 @@ var InMemberOfClass = (function () { function InMemberOfClass() { } InMemberOfClass.prototype.inThis = function () { - if ('a' in this.prop) { + if ("a" in this.prop) { var y = this.prop.a; } else { @@ -169,12 +203,12 @@ var InMemberOfClass = (function () { }; return InMemberOfClass; }()); -//added for completeness +// added for completeness var SelfAssert = (function () { function SelfAssert() { } SelfAssert.prototype.inThis = function () { - if ('a' in this) { + if ("a" in this) { var y = this.a; } else { diff --git a/tests/baselines/reference/typeGuardOfFromPropNameInUnionType.symbols b/tests/baselines/reference/typeGuardOfFromPropNameInUnionType.symbols index 0302635b55..72fb3df2fc 100644 --- a/tests/baselines/reference/typeGuardOfFromPropNameInUnionType.symbols +++ b/tests/baselines/reference/typeGuardOfFromPropNameInUnionType.symbols @@ -17,234 +17,273 @@ class D { a: Date; } >a : Symbol(D.a, Decl(typeGuardOfFromPropNameInUnionType.ts, 3, 9)) >Date : Symbol(Date, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) -class ClassWithProp { prop: A | B } ->ClassWithProp : Symbol(ClassWithProp, Decl(typeGuardOfFromPropNameInUnionType.ts, 3, 20)) ->prop : Symbol(ClassWithProp.prop, Decl(typeGuardOfFromPropNameInUnionType.ts, 4, 21)) ->A : Symbol(A, Decl(typeGuardOfFromPropNameInUnionType.ts, 0, 0)) ->B : Symbol(B, Decl(typeGuardOfFromPropNameInUnionType.ts, 0, 22)) - -class NestedClassWithProp { outer: ClassWithProp } ->NestedClassWithProp : Symbol(NestedClassWithProp, Decl(typeGuardOfFromPropNameInUnionType.ts, 4, 35)) ->outer : Symbol(NestedClassWithProp.outer, Decl(typeGuardOfFromPropNameInUnionType.ts, 5, 27)) ->ClassWithProp : Symbol(ClassWithProp, Decl(typeGuardOfFromPropNameInUnionType.ts, 3, 20)) - function namedClasses(x: A | B) { ->namedClasses : Symbol(namedClasses, Decl(typeGuardOfFromPropNameInUnionType.ts, 5, 50)) ->x : Symbol(x, Decl(typeGuardOfFromPropNameInUnionType.ts, 7, 22)) +>namedClasses : Symbol(namedClasses, Decl(typeGuardOfFromPropNameInUnionType.ts, 3, 20)) +>x : Symbol(x, Decl(typeGuardOfFromPropNameInUnionType.ts, 5, 22)) >A : Symbol(A, Decl(typeGuardOfFromPropNameInUnionType.ts, 0, 0)) >B : Symbol(B, Decl(typeGuardOfFromPropNameInUnionType.ts, 0, 22)) if ("a" in x) { ->x : Symbol(x, Decl(typeGuardOfFromPropNameInUnionType.ts, 7, 22)) +>x : Symbol(x, Decl(typeGuardOfFromPropNameInUnionType.ts, 5, 22)) x.a = "1"; >x.a : Symbol(A.a, Decl(typeGuardOfFromPropNameInUnionType.ts, 0, 9)) ->x : Symbol(x, Decl(typeGuardOfFromPropNameInUnionType.ts, 7, 22)) +>x : Symbol(x, Decl(typeGuardOfFromPropNameInUnionType.ts, 5, 22)) >a : Symbol(A.a, Decl(typeGuardOfFromPropNameInUnionType.ts, 0, 9)) } else { x.b = 1; >x.b : Symbol(B.b, Decl(typeGuardOfFromPropNameInUnionType.ts, 1, 9)) ->x : Symbol(x, Decl(typeGuardOfFromPropNameInUnionType.ts, 7, 22)) +>x : Symbol(x, Decl(typeGuardOfFromPropNameInUnionType.ts, 5, 22)) >b : Symbol(B.b, Decl(typeGuardOfFromPropNameInUnionType.ts, 1, 9)) } } function multipleClasses(x: A | B | C | D) { ->multipleClasses : Symbol(multipleClasses, Decl(typeGuardOfFromPropNameInUnionType.ts, 13, 1)) ->x : Symbol(x, Decl(typeGuardOfFromPropNameInUnionType.ts, 15, 25)) +>multipleClasses : Symbol(multipleClasses, Decl(typeGuardOfFromPropNameInUnionType.ts, 11, 1)) +>x : Symbol(x, Decl(typeGuardOfFromPropNameInUnionType.ts, 13, 25)) >A : Symbol(A, Decl(typeGuardOfFromPropNameInUnionType.ts, 0, 0)) >B : Symbol(B, Decl(typeGuardOfFromPropNameInUnionType.ts, 0, 22)) >C : Symbol(C, Decl(typeGuardOfFromPropNameInUnionType.ts, 1, 22)) >D : Symbol(D, Decl(typeGuardOfFromPropNameInUnionType.ts, 2, 22)) if ("a" in x) { ->x : Symbol(x, Decl(typeGuardOfFromPropNameInUnionType.ts, 15, 25)) +>x : Symbol(x, Decl(typeGuardOfFromPropNameInUnionType.ts, 13, 25)) let y: string | Date = x.a; ->y : Symbol(y, Decl(typeGuardOfFromPropNameInUnionType.ts, 17, 11)) +>y : Symbol(y, Decl(typeGuardOfFromPropNameInUnionType.ts, 15, 11)) >Date : Symbol(Date, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) >x.a : Symbol(a, Decl(typeGuardOfFromPropNameInUnionType.ts, 0, 9), Decl(typeGuardOfFromPropNameInUnionType.ts, 3, 9)) ->x : Symbol(x, Decl(typeGuardOfFromPropNameInUnionType.ts, 15, 25)) +>x : Symbol(x, Decl(typeGuardOfFromPropNameInUnionType.ts, 13, 25)) >a : Symbol(a, Decl(typeGuardOfFromPropNameInUnionType.ts, 0, 9), Decl(typeGuardOfFromPropNameInUnionType.ts, 3, 9)) } else { let z: number | Object = x.b; ->z : Symbol(z, Decl(typeGuardOfFromPropNameInUnionType.ts, 19, 11)) +>z : Symbol(z, Decl(typeGuardOfFromPropNameInUnionType.ts, 17, 11)) >Object : Symbol(Object, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) >x.b : Symbol(b, Decl(typeGuardOfFromPropNameInUnionType.ts, 1, 9), Decl(typeGuardOfFromPropNameInUnionType.ts, 2, 9)) ->x : Symbol(x, Decl(typeGuardOfFromPropNameInUnionType.ts, 15, 25)) +>x : Symbol(x, Decl(typeGuardOfFromPropNameInUnionType.ts, 13, 25)) >b : Symbol(b, Decl(typeGuardOfFromPropNameInUnionType.ts, 1, 9), Decl(typeGuardOfFromPropNameInUnionType.ts, 2, 9)) } } function anonymousClasses(x: { a: string; } | { b: number; }) { ->anonymousClasses : Symbol(anonymousClasses, Decl(typeGuardOfFromPropNameInUnionType.ts, 21, 1)) ->x : Symbol(x, Decl(typeGuardOfFromPropNameInUnionType.ts, 23, 26)) ->a : Symbol(a, Decl(typeGuardOfFromPropNameInUnionType.ts, 23, 30)) ->b : Symbol(b, Decl(typeGuardOfFromPropNameInUnionType.ts, 23, 47)) +>anonymousClasses : Symbol(anonymousClasses, Decl(typeGuardOfFromPropNameInUnionType.ts, 19, 1)) +>x : Symbol(x, Decl(typeGuardOfFromPropNameInUnionType.ts, 21, 26)) +>a : Symbol(a, Decl(typeGuardOfFromPropNameInUnionType.ts, 21, 30)) +>b : Symbol(b, Decl(typeGuardOfFromPropNameInUnionType.ts, 21, 47)) if ("a" in x) { ->x : Symbol(x, Decl(typeGuardOfFromPropNameInUnionType.ts, 23, 26)) +>x : Symbol(x, Decl(typeGuardOfFromPropNameInUnionType.ts, 21, 26)) let y: string = x.a; ->y : Symbol(y, Decl(typeGuardOfFromPropNameInUnionType.ts, 25, 11)) ->x.a : Symbol(a, Decl(typeGuardOfFromPropNameInUnionType.ts, 23, 30)) ->x : Symbol(x, Decl(typeGuardOfFromPropNameInUnionType.ts, 23, 26)) ->a : Symbol(a, Decl(typeGuardOfFromPropNameInUnionType.ts, 23, 30)) +>y : Symbol(y, Decl(typeGuardOfFromPropNameInUnionType.ts, 23, 11)) +>x.a : Symbol(a, Decl(typeGuardOfFromPropNameInUnionType.ts, 21, 30)) +>x : Symbol(x, Decl(typeGuardOfFromPropNameInUnionType.ts, 21, 26)) +>a : Symbol(a, Decl(typeGuardOfFromPropNameInUnionType.ts, 21, 30)) } else { let z: number = x.b; ->z : Symbol(z, Decl(typeGuardOfFromPropNameInUnionType.ts, 27, 11)) ->x.b : Symbol(b, Decl(typeGuardOfFromPropNameInUnionType.ts, 23, 47)) ->x : Symbol(x, Decl(typeGuardOfFromPropNameInUnionType.ts, 23, 26)) ->b : Symbol(b, Decl(typeGuardOfFromPropNameInUnionType.ts, 23, 47)) +>z : Symbol(z, Decl(typeGuardOfFromPropNameInUnionType.ts, 25, 11)) +>x.b : Symbol(b, Decl(typeGuardOfFromPropNameInUnionType.ts, 21, 47)) +>x : Symbol(x, Decl(typeGuardOfFromPropNameInUnionType.ts, 21, 26)) +>b : Symbol(b, Decl(typeGuardOfFromPropNameInUnionType.ts, 21, 47)) } } + +class AWithOptionalProp { a?: string; } +>AWithOptionalProp : Symbol(AWithOptionalProp, Decl(typeGuardOfFromPropNameInUnionType.ts, 27, 1)) +>a : Symbol(AWithOptionalProp.a, Decl(typeGuardOfFromPropNameInUnionType.ts, 29, 25)) + +class BWithOptionalProp { b?: string; } +>BWithOptionalProp : Symbol(BWithOptionalProp, Decl(typeGuardOfFromPropNameInUnionType.ts, 29, 39)) +>b : Symbol(BWithOptionalProp.b, Decl(typeGuardOfFromPropNameInUnionType.ts, 30, 25)) + +function positiveTestClassesWithOptionalProperties(x: AWithOptionalProp | BWithOptionalProp) { +>positiveTestClassesWithOptionalProperties : Symbol(positiveTestClassesWithOptionalProperties, Decl(typeGuardOfFromPropNameInUnionType.ts, 30, 39)) +>x : Symbol(x, Decl(typeGuardOfFromPropNameInUnionType.ts, 32, 51)) +>AWithOptionalProp : Symbol(AWithOptionalProp, Decl(typeGuardOfFromPropNameInUnionType.ts, 27, 1)) +>BWithOptionalProp : Symbol(BWithOptionalProp, Decl(typeGuardOfFromPropNameInUnionType.ts, 29, 39)) + + if ("a" in x) { +>x : Symbol(x, Decl(typeGuardOfFromPropNameInUnionType.ts, 32, 51)) + + x.a = "1"; +>x.a : Symbol(AWithOptionalProp.a, Decl(typeGuardOfFromPropNameInUnionType.ts, 29, 25)) +>x : Symbol(x, Decl(typeGuardOfFromPropNameInUnionType.ts, 32, 51)) +>a : Symbol(AWithOptionalProp.a, Decl(typeGuardOfFromPropNameInUnionType.ts, 29, 25)) + + } else { + const y: string = x instanceof AWithOptionalProp +>y : Symbol(y, Decl(typeGuardOfFromPropNameInUnionType.ts, 36, 13)) +>x : Symbol(x, Decl(typeGuardOfFromPropNameInUnionType.ts, 32, 51)) +>AWithOptionalProp : Symbol(AWithOptionalProp, Decl(typeGuardOfFromPropNameInUnionType.ts, 27, 1)) + + ? x.a +>x.a : Symbol(AWithOptionalProp.a, Decl(typeGuardOfFromPropNameInUnionType.ts, 29, 25)) +>x : Symbol(x, Decl(typeGuardOfFromPropNameInUnionType.ts, 32, 51)) +>a : Symbol(AWithOptionalProp.a, Decl(typeGuardOfFromPropNameInUnionType.ts, 29, 25)) + + : x.b +>x.b : Symbol(BWithOptionalProp.b, Decl(typeGuardOfFromPropNameInUnionType.ts, 30, 25)) +>x : Symbol(x, Decl(typeGuardOfFromPropNameInUnionType.ts, 32, 51)) +>b : Symbol(BWithOptionalProp.b, Decl(typeGuardOfFromPropNameInUnionType.ts, 30, 25)) + } +} + function inParenthesizedExpression(x: A | B) { ->inParenthesizedExpression : Symbol(inParenthesizedExpression, Decl(typeGuardOfFromPropNameInUnionType.ts, 29, 1)) ->x : Symbol(x, Decl(typeGuardOfFromPropNameInUnionType.ts, 30, 35)) +>inParenthesizedExpression : Symbol(inParenthesizedExpression, Decl(typeGuardOfFromPropNameInUnionType.ts, 40, 1)) +>x : Symbol(x, Decl(typeGuardOfFromPropNameInUnionType.ts, 42, 35)) >A : Symbol(A, Decl(typeGuardOfFromPropNameInUnionType.ts, 0, 0)) >B : Symbol(B, Decl(typeGuardOfFromPropNameInUnionType.ts, 0, 22)) if ("a" in (x)) { ->x : Symbol(x, Decl(typeGuardOfFromPropNameInUnionType.ts, 30, 35)) +>x : Symbol(x, Decl(typeGuardOfFromPropNameInUnionType.ts, 42, 35)) let y: string = x.a; ->y : Symbol(y, Decl(typeGuardOfFromPropNameInUnionType.ts, 32, 11)) +>y : Symbol(y, Decl(typeGuardOfFromPropNameInUnionType.ts, 44, 11)) >x.a : Symbol(A.a, Decl(typeGuardOfFromPropNameInUnionType.ts, 0, 9)) ->x : Symbol(x, Decl(typeGuardOfFromPropNameInUnionType.ts, 30, 35)) +>x : Symbol(x, Decl(typeGuardOfFromPropNameInUnionType.ts, 42, 35)) >a : Symbol(A.a, Decl(typeGuardOfFromPropNameInUnionType.ts, 0, 9)) } else { let z: number = x.b; ->z : Symbol(z, Decl(typeGuardOfFromPropNameInUnionType.ts, 34, 11)) +>z : Symbol(z, Decl(typeGuardOfFromPropNameInUnionType.ts, 46, 11)) >x.b : Symbol(B.b, Decl(typeGuardOfFromPropNameInUnionType.ts, 1, 9)) ->x : Symbol(x, Decl(typeGuardOfFromPropNameInUnionType.ts, 30, 35)) +>x : Symbol(x, Decl(typeGuardOfFromPropNameInUnionType.ts, 42, 35)) >b : Symbol(B.b, Decl(typeGuardOfFromPropNameInUnionType.ts, 1, 9)) } } +class ClassWithUnionProp { prop: A | B; } +>ClassWithUnionProp : Symbol(ClassWithUnionProp, Decl(typeGuardOfFromPropNameInUnionType.ts, 48, 1)) +>prop : Symbol(ClassWithUnionProp.prop, Decl(typeGuardOfFromPropNameInUnionType.ts, 50, 26)) +>A : Symbol(A, Decl(typeGuardOfFromPropNameInUnionType.ts, 0, 0)) +>B : Symbol(B, Decl(typeGuardOfFromPropNameInUnionType.ts, 0, 22)) -function inProperty(x: ClassWithProp) { ->inProperty : Symbol(inProperty, Decl(typeGuardOfFromPropNameInUnionType.ts, 36, 1)) ->x : Symbol(x, Decl(typeGuardOfFromPropNameInUnionType.ts, 39, 20)) ->ClassWithProp : Symbol(ClassWithProp, Decl(typeGuardOfFromPropNameInUnionType.ts, 3, 20)) +function inProperty(x: ClassWithUnionProp) { +>inProperty : Symbol(inProperty, Decl(typeGuardOfFromPropNameInUnionType.ts, 50, 41)) +>x : Symbol(x, Decl(typeGuardOfFromPropNameInUnionType.ts, 52, 20)) +>ClassWithUnionProp : Symbol(ClassWithUnionProp, Decl(typeGuardOfFromPropNameInUnionType.ts, 48, 1)) if ("a" in x.prop) { ->x.prop : Symbol(ClassWithProp.prop, Decl(typeGuardOfFromPropNameInUnionType.ts, 4, 21)) ->x : Symbol(x, Decl(typeGuardOfFromPropNameInUnionType.ts, 39, 20)) ->prop : Symbol(ClassWithProp.prop, Decl(typeGuardOfFromPropNameInUnionType.ts, 4, 21)) +>x.prop : Symbol(ClassWithUnionProp.prop, Decl(typeGuardOfFromPropNameInUnionType.ts, 50, 26)) +>x : Symbol(x, Decl(typeGuardOfFromPropNameInUnionType.ts, 52, 20)) +>prop : Symbol(ClassWithUnionProp.prop, Decl(typeGuardOfFromPropNameInUnionType.ts, 50, 26)) let y: string = x.prop.a; ->y : Symbol(y, Decl(typeGuardOfFromPropNameInUnionType.ts, 41, 11)) +>y : Symbol(y, Decl(typeGuardOfFromPropNameInUnionType.ts, 54, 11)) >x.prop.a : Symbol(A.a, Decl(typeGuardOfFromPropNameInUnionType.ts, 0, 9)) ->x.prop : Symbol(ClassWithProp.prop, Decl(typeGuardOfFromPropNameInUnionType.ts, 4, 21)) ->x : Symbol(x, Decl(typeGuardOfFromPropNameInUnionType.ts, 39, 20)) ->prop : Symbol(ClassWithProp.prop, Decl(typeGuardOfFromPropNameInUnionType.ts, 4, 21)) +>x.prop : Symbol(ClassWithUnionProp.prop, Decl(typeGuardOfFromPropNameInUnionType.ts, 50, 26)) +>x : Symbol(x, Decl(typeGuardOfFromPropNameInUnionType.ts, 52, 20)) +>prop : Symbol(ClassWithUnionProp.prop, Decl(typeGuardOfFromPropNameInUnionType.ts, 50, 26)) >a : Symbol(A.a, Decl(typeGuardOfFromPropNameInUnionType.ts, 0, 9)) } else { let z: number = x.prop.b; ->z : Symbol(z, Decl(typeGuardOfFromPropNameInUnionType.ts, 43, 11)) +>z : Symbol(z, Decl(typeGuardOfFromPropNameInUnionType.ts, 56, 11)) >x.prop.b : Symbol(B.b, Decl(typeGuardOfFromPropNameInUnionType.ts, 1, 9)) ->x.prop : Symbol(ClassWithProp.prop, Decl(typeGuardOfFromPropNameInUnionType.ts, 4, 21)) ->x : Symbol(x, Decl(typeGuardOfFromPropNameInUnionType.ts, 39, 20)) ->prop : Symbol(ClassWithProp.prop, Decl(typeGuardOfFromPropNameInUnionType.ts, 4, 21)) +>x.prop : Symbol(ClassWithUnionProp.prop, Decl(typeGuardOfFromPropNameInUnionType.ts, 50, 26)) +>x : Symbol(x, Decl(typeGuardOfFromPropNameInUnionType.ts, 52, 20)) +>prop : Symbol(ClassWithUnionProp.prop, Decl(typeGuardOfFromPropNameInUnionType.ts, 50, 26)) >b : Symbol(B.b, Decl(typeGuardOfFromPropNameInUnionType.ts, 1, 9)) } } +class NestedClassWithProp { outer: ClassWithUnionProp; } +>NestedClassWithProp : Symbol(NestedClassWithProp, Decl(typeGuardOfFromPropNameInUnionType.ts, 58, 1)) +>outer : Symbol(NestedClassWithProp.outer, Decl(typeGuardOfFromPropNameInUnionType.ts, 60, 27)) +>ClassWithUnionProp : Symbol(ClassWithUnionProp, Decl(typeGuardOfFromPropNameInUnionType.ts, 48, 1)) function innestedProperty(x: NestedClassWithProp) { ->innestedProperty : Symbol(innestedProperty, Decl(typeGuardOfFromPropNameInUnionType.ts, 45, 1)) ->x : Symbol(x, Decl(typeGuardOfFromPropNameInUnionType.ts, 48, 26)) ->NestedClassWithProp : Symbol(NestedClassWithProp, Decl(typeGuardOfFromPropNameInUnionType.ts, 4, 35)) +>innestedProperty : Symbol(innestedProperty, Decl(typeGuardOfFromPropNameInUnionType.ts, 60, 56)) +>x : Symbol(x, Decl(typeGuardOfFromPropNameInUnionType.ts, 62, 26)) +>NestedClassWithProp : Symbol(NestedClassWithProp, Decl(typeGuardOfFromPropNameInUnionType.ts, 58, 1)) if ("a" in x.outer.prop) { ->x.outer.prop : Symbol(ClassWithProp.prop, Decl(typeGuardOfFromPropNameInUnionType.ts, 4, 21)) ->x.outer : Symbol(NestedClassWithProp.outer, Decl(typeGuardOfFromPropNameInUnionType.ts, 5, 27)) ->x : Symbol(x, Decl(typeGuardOfFromPropNameInUnionType.ts, 48, 26)) ->outer : Symbol(NestedClassWithProp.outer, Decl(typeGuardOfFromPropNameInUnionType.ts, 5, 27)) ->prop : Symbol(ClassWithProp.prop, Decl(typeGuardOfFromPropNameInUnionType.ts, 4, 21)) +>x.outer.prop : Symbol(ClassWithUnionProp.prop, Decl(typeGuardOfFromPropNameInUnionType.ts, 50, 26)) +>x.outer : Symbol(NestedClassWithProp.outer, Decl(typeGuardOfFromPropNameInUnionType.ts, 60, 27)) +>x : Symbol(x, Decl(typeGuardOfFromPropNameInUnionType.ts, 62, 26)) +>outer : Symbol(NestedClassWithProp.outer, Decl(typeGuardOfFromPropNameInUnionType.ts, 60, 27)) +>prop : Symbol(ClassWithUnionProp.prop, Decl(typeGuardOfFromPropNameInUnionType.ts, 50, 26)) let y: string = x.outer.prop.a; ->y : Symbol(y, Decl(typeGuardOfFromPropNameInUnionType.ts, 50, 11)) +>y : Symbol(y, Decl(typeGuardOfFromPropNameInUnionType.ts, 64, 11)) >x.outer.prop.a : Symbol(A.a, Decl(typeGuardOfFromPropNameInUnionType.ts, 0, 9)) ->x.outer.prop : Symbol(ClassWithProp.prop, Decl(typeGuardOfFromPropNameInUnionType.ts, 4, 21)) ->x.outer : Symbol(NestedClassWithProp.outer, Decl(typeGuardOfFromPropNameInUnionType.ts, 5, 27)) ->x : Symbol(x, Decl(typeGuardOfFromPropNameInUnionType.ts, 48, 26)) ->outer : Symbol(NestedClassWithProp.outer, Decl(typeGuardOfFromPropNameInUnionType.ts, 5, 27)) ->prop : Symbol(ClassWithProp.prop, Decl(typeGuardOfFromPropNameInUnionType.ts, 4, 21)) +>x.outer.prop : Symbol(ClassWithUnionProp.prop, Decl(typeGuardOfFromPropNameInUnionType.ts, 50, 26)) +>x.outer : Symbol(NestedClassWithProp.outer, Decl(typeGuardOfFromPropNameInUnionType.ts, 60, 27)) +>x : Symbol(x, Decl(typeGuardOfFromPropNameInUnionType.ts, 62, 26)) +>outer : Symbol(NestedClassWithProp.outer, Decl(typeGuardOfFromPropNameInUnionType.ts, 60, 27)) +>prop : Symbol(ClassWithUnionProp.prop, Decl(typeGuardOfFromPropNameInUnionType.ts, 50, 26)) >a : Symbol(A.a, Decl(typeGuardOfFromPropNameInUnionType.ts, 0, 9)) } else { let z: number = x.outer.prop.b; ->z : Symbol(z, Decl(typeGuardOfFromPropNameInUnionType.ts, 52, 11)) +>z : Symbol(z, Decl(typeGuardOfFromPropNameInUnionType.ts, 66, 11)) >x.outer.prop.b : Symbol(B.b, Decl(typeGuardOfFromPropNameInUnionType.ts, 1, 9)) ->x.outer.prop : Symbol(ClassWithProp.prop, Decl(typeGuardOfFromPropNameInUnionType.ts, 4, 21)) ->x.outer : Symbol(NestedClassWithProp.outer, Decl(typeGuardOfFromPropNameInUnionType.ts, 5, 27)) ->x : Symbol(x, Decl(typeGuardOfFromPropNameInUnionType.ts, 48, 26)) ->outer : Symbol(NestedClassWithProp.outer, Decl(typeGuardOfFromPropNameInUnionType.ts, 5, 27)) ->prop : Symbol(ClassWithProp.prop, Decl(typeGuardOfFromPropNameInUnionType.ts, 4, 21)) +>x.outer.prop : Symbol(ClassWithUnionProp.prop, Decl(typeGuardOfFromPropNameInUnionType.ts, 50, 26)) +>x.outer : Symbol(NestedClassWithProp.outer, Decl(typeGuardOfFromPropNameInUnionType.ts, 60, 27)) +>x : Symbol(x, Decl(typeGuardOfFromPropNameInUnionType.ts, 62, 26)) +>outer : Symbol(NestedClassWithProp.outer, Decl(typeGuardOfFromPropNameInUnionType.ts, 60, 27)) +>prop : Symbol(ClassWithUnionProp.prop, Decl(typeGuardOfFromPropNameInUnionType.ts, 50, 26)) >b : Symbol(B.b, Decl(typeGuardOfFromPropNameInUnionType.ts, 1, 9)) } } class InMemberOfClass { ->InMemberOfClass : Symbol(InMemberOfClass, Decl(typeGuardOfFromPropNameInUnionType.ts, 54, 1)) +>InMemberOfClass : Symbol(InMemberOfClass, Decl(typeGuardOfFromPropNameInUnionType.ts, 68, 1)) protected prop: A | B; ->prop : Symbol(InMemberOfClass.prop, Decl(typeGuardOfFromPropNameInUnionType.ts, 56, 23)) +>prop : Symbol(InMemberOfClass.prop, Decl(typeGuardOfFromPropNameInUnionType.ts, 70, 23)) >A : Symbol(A, Decl(typeGuardOfFromPropNameInUnionType.ts, 0, 0)) >B : Symbol(B, Decl(typeGuardOfFromPropNameInUnionType.ts, 0, 22)) inThis() { ->inThis : Symbol(InMemberOfClass.inThis, Decl(typeGuardOfFromPropNameInUnionType.ts, 57, 26)) +>inThis : Symbol(InMemberOfClass.inThis, Decl(typeGuardOfFromPropNameInUnionType.ts, 71, 26)) - if ('a' in this.prop) { ->this.prop : Symbol(InMemberOfClass.prop, Decl(typeGuardOfFromPropNameInUnionType.ts, 56, 23)) ->this : Symbol(InMemberOfClass, Decl(typeGuardOfFromPropNameInUnionType.ts, 54, 1)) ->prop : Symbol(InMemberOfClass.prop, Decl(typeGuardOfFromPropNameInUnionType.ts, 56, 23)) + if ("a" in this.prop) { +>this.prop : Symbol(InMemberOfClass.prop, Decl(typeGuardOfFromPropNameInUnionType.ts, 70, 23)) +>this : Symbol(InMemberOfClass, Decl(typeGuardOfFromPropNameInUnionType.ts, 68, 1)) +>prop : Symbol(InMemberOfClass.prop, Decl(typeGuardOfFromPropNameInUnionType.ts, 70, 23)) let y: string = this.prop.a; ->y : Symbol(y, Decl(typeGuardOfFromPropNameInUnionType.ts, 60, 15)) +>y : Symbol(y, Decl(typeGuardOfFromPropNameInUnionType.ts, 74, 15)) >this.prop.a : Symbol(A.a, Decl(typeGuardOfFromPropNameInUnionType.ts, 0, 9)) ->this.prop : Symbol(InMemberOfClass.prop, Decl(typeGuardOfFromPropNameInUnionType.ts, 56, 23)) ->this : Symbol(InMemberOfClass, Decl(typeGuardOfFromPropNameInUnionType.ts, 54, 1)) ->prop : Symbol(InMemberOfClass.prop, Decl(typeGuardOfFromPropNameInUnionType.ts, 56, 23)) +>this.prop : Symbol(InMemberOfClass.prop, Decl(typeGuardOfFromPropNameInUnionType.ts, 70, 23)) +>this : Symbol(InMemberOfClass, Decl(typeGuardOfFromPropNameInUnionType.ts, 68, 1)) +>prop : Symbol(InMemberOfClass.prop, Decl(typeGuardOfFromPropNameInUnionType.ts, 70, 23)) >a : Symbol(A.a, Decl(typeGuardOfFromPropNameInUnionType.ts, 0, 9)) } else { let z: number = this.prop.b; ->z : Symbol(z, Decl(typeGuardOfFromPropNameInUnionType.ts, 62, 15)) +>z : Symbol(z, Decl(typeGuardOfFromPropNameInUnionType.ts, 76, 15)) >this.prop.b : Symbol(B.b, Decl(typeGuardOfFromPropNameInUnionType.ts, 1, 9)) ->this.prop : Symbol(InMemberOfClass.prop, Decl(typeGuardOfFromPropNameInUnionType.ts, 56, 23)) ->this : Symbol(InMemberOfClass, Decl(typeGuardOfFromPropNameInUnionType.ts, 54, 1)) ->prop : Symbol(InMemberOfClass.prop, Decl(typeGuardOfFromPropNameInUnionType.ts, 56, 23)) +>this.prop : Symbol(InMemberOfClass.prop, Decl(typeGuardOfFromPropNameInUnionType.ts, 70, 23)) +>this : Symbol(InMemberOfClass, Decl(typeGuardOfFromPropNameInUnionType.ts, 68, 1)) +>prop : Symbol(InMemberOfClass.prop, Decl(typeGuardOfFromPropNameInUnionType.ts, 70, 23)) >b : Symbol(B.b, Decl(typeGuardOfFromPropNameInUnionType.ts, 1, 9)) } } } -//added for completeness +// added for completeness class SelfAssert { ->SelfAssert : Symbol(SelfAssert, Decl(typeGuardOfFromPropNameInUnionType.ts, 65, 1)) +>SelfAssert : Symbol(SelfAssert, Decl(typeGuardOfFromPropNameInUnionType.ts, 79, 1)) a: string; ->a : Symbol(SelfAssert.a, Decl(typeGuardOfFromPropNameInUnionType.ts, 68, 18)) +>a : Symbol(SelfAssert.a, Decl(typeGuardOfFromPropNameInUnionType.ts, 82, 18)) inThis() { ->inThis : Symbol(SelfAssert.inThis, Decl(typeGuardOfFromPropNameInUnionType.ts, 69, 14)) +>inThis : Symbol(SelfAssert.inThis, Decl(typeGuardOfFromPropNameInUnionType.ts, 83, 14)) - if ('a' in this) { ->this : Symbol(SelfAssert, Decl(typeGuardOfFromPropNameInUnionType.ts, 65, 1)) + if ("a" in this) { +>this : Symbol(SelfAssert, Decl(typeGuardOfFromPropNameInUnionType.ts, 79, 1)) let y: string = this.a; ->y : Symbol(y, Decl(typeGuardOfFromPropNameInUnionType.ts, 72, 15)) ->this.a : Symbol(SelfAssert.a, Decl(typeGuardOfFromPropNameInUnionType.ts, 68, 18)) ->this : Symbol(SelfAssert, Decl(typeGuardOfFromPropNameInUnionType.ts, 65, 1)) ->a : Symbol(SelfAssert.a, Decl(typeGuardOfFromPropNameInUnionType.ts, 68, 18)) +>y : Symbol(y, Decl(typeGuardOfFromPropNameInUnionType.ts, 86, 15)) +>this.a : Symbol(SelfAssert.a, Decl(typeGuardOfFromPropNameInUnionType.ts, 82, 18)) +>this : Symbol(SelfAssert, Decl(typeGuardOfFromPropNameInUnionType.ts, 79, 1)) +>a : Symbol(SelfAssert.a, Decl(typeGuardOfFromPropNameInUnionType.ts, 82, 18)) } else { } diff --git a/tests/baselines/reference/typeGuardOfFromPropNameInUnionType.types b/tests/baselines/reference/typeGuardOfFromPropNameInUnionType.types index d9984840fb..4aff12ae07 100644 --- a/tests/baselines/reference/typeGuardOfFromPropNameInUnionType.types +++ b/tests/baselines/reference/typeGuardOfFromPropNameInUnionType.types @@ -17,17 +17,6 @@ class D { a: Date; } >a : Date >Date : Date -class ClassWithProp { prop: A | B } ->ClassWithProp : ClassWithProp ->prop : A | B ->A : A ->B : B - -class NestedClassWithProp { outer: ClassWithProp } ->NestedClassWithProp : NestedClassWithProp ->outer : ClassWithProp ->ClassWithProp : ClassWithProp - function namedClasses(x: A | B) { >namedClasses : (x: A | B) => void >x : A | B @@ -111,6 +100,53 @@ function anonymousClasses(x: { a: string; } | { b: number; }) { >b : number } } + +class AWithOptionalProp { a?: string; } +>AWithOptionalProp : AWithOptionalProp +>a : string + +class BWithOptionalProp { b?: string; } +>BWithOptionalProp : BWithOptionalProp +>b : string + +function positiveTestClassesWithOptionalProperties(x: AWithOptionalProp | BWithOptionalProp) { +>positiveTestClassesWithOptionalProperties : (x: AWithOptionalProp | BWithOptionalProp) => void +>x : AWithOptionalProp | BWithOptionalProp +>AWithOptionalProp : AWithOptionalProp +>BWithOptionalProp : BWithOptionalProp + + if ("a" in x) { +>"a" in x : boolean +>"a" : "a" +>x : AWithOptionalProp | BWithOptionalProp + + x.a = "1"; +>x.a = "1" : "1" +>x.a : string +>x : AWithOptionalProp +>a : string +>"1" : "1" + + } else { + const y: string = x instanceof AWithOptionalProp +>y : string +>x instanceof AWithOptionalProp ? x.a : x.b : string +>x instanceof AWithOptionalProp : boolean +>x : AWithOptionalProp | BWithOptionalProp +>AWithOptionalProp : typeof AWithOptionalProp + + ? x.a +>x.a : string +>x : AWithOptionalProp +>a : string + + : x.b +>x.b : string +>x : BWithOptionalProp +>b : string + } +} + function inParenthesizedExpression(x: A | B) { >inParenthesizedExpression : (x: A | B) => void >x : A | B @@ -138,24 +174,29 @@ function inParenthesizedExpression(x: A | B) { } } +class ClassWithUnionProp { prop: A | B; } +>ClassWithUnionProp : ClassWithUnionProp +>prop : A | B +>A : A +>B : B -function inProperty(x: ClassWithProp) { ->inProperty : (x: ClassWithProp) => void ->x : ClassWithProp ->ClassWithProp : ClassWithProp +function inProperty(x: ClassWithUnionProp) { +>inProperty : (x: ClassWithUnionProp) => void +>x : ClassWithUnionProp +>ClassWithUnionProp : ClassWithUnionProp if ("a" in x.prop) { >"a" in x.prop : boolean >"a" : "a" >x.prop : A | B ->x : ClassWithProp +>x : ClassWithUnionProp >prop : A | B let y: string = x.prop.a; >y : string >x.prop.a : string >x.prop : A ->x : ClassWithProp +>x : ClassWithUnionProp >prop : A >a : string @@ -164,12 +205,16 @@ function inProperty(x: ClassWithProp) { >z : number >x.prop.b : number >x.prop : B ->x : ClassWithProp +>x : ClassWithUnionProp >prop : B >b : number } } +class NestedClassWithProp { outer: ClassWithUnionProp; } +>NestedClassWithProp : NestedClassWithProp +>outer : ClassWithUnionProp +>ClassWithUnionProp : ClassWithUnionProp function innestedProperty(x: NestedClassWithProp) { >innestedProperty : (x: NestedClassWithProp) => void @@ -180,18 +225,18 @@ function innestedProperty(x: NestedClassWithProp) { >"a" in x.outer.prop : boolean >"a" : "a" >x.outer.prop : A | B ->x.outer : ClassWithProp +>x.outer : ClassWithUnionProp >x : NestedClassWithProp ->outer : ClassWithProp +>outer : ClassWithUnionProp >prop : A | B let y: string = x.outer.prop.a; >y : string >x.outer.prop.a : string >x.outer.prop : A ->x.outer : ClassWithProp +>x.outer : ClassWithUnionProp >x : NestedClassWithProp ->outer : ClassWithProp +>outer : ClassWithUnionProp >prop : A >a : string @@ -200,9 +245,9 @@ function innestedProperty(x: NestedClassWithProp) { >z : number >x.outer.prop.b : number >x.outer.prop : B ->x.outer : ClassWithProp +>x.outer : ClassWithUnionProp >x : NestedClassWithProp ->outer : ClassWithProp +>outer : ClassWithUnionProp >prop : B >b : number } @@ -219,9 +264,9 @@ class InMemberOfClass { inThis() { >inThis : () => void - if ('a' in this.prop) { ->'a' in this.prop : boolean ->'a' : "a" + if ("a" in this.prop) { +>"a" in this.prop : boolean +>"a" : "a" >this.prop : A | B >this : this >prop : A | B @@ -246,7 +291,7 @@ class InMemberOfClass { } } -//added for completeness +// added for completeness class SelfAssert { >SelfAssert : SelfAssert @@ -256,9 +301,9 @@ class SelfAssert { inThis() { >inThis : () => void - if ('a' in this) { ->'a' in this : boolean ->'a' : "a" + if ("a" in this) { +>"a" in this : boolean +>"a" : "a" >this : this let y: string = this.a; diff --git a/tests/cases/compiler/inKeywordTypeguard.ts b/tests/cases/compiler/inKeywordTypeguard.ts index 90d1942e7c..bbab20afc6 100644 --- a/tests/cases/compiler/inKeywordTypeguard.ts +++ b/tests/cases/compiler/inKeywordTypeguard.ts @@ -1,97 +1,97 @@ -class A { a: string; } -class B { b: string; } - -function negativeClassesTest(x: A | B) { - if ("a" in x) { - x.b = "1"; - } else { - x.a = "1"; - } -} - -function positiveClassesTest(x: A | B) { - if ("a" in x) { - x.b = "1"; - } else { - x.a = "1"; - } -} - -class AOpt { a?: string } -class BOpn { b?: string } - -function positiveTestClassesWithOptionalProperties(x: AOpt | BOpn) { - if ("a" in x) { - x.a = "1"; - } else { - x.b = "1"; - } -} - -class AWithMethod { - a(): string { return "" } -} - -class BWithMethod { - b(): string { return "" } -} - -function negativeTestClassesWithMembers(x: AWithMethod | BWithMethod) { - if ("a" in x) { - x.a(); - x.b(); - } else { - } -} - -function negativeTestClassesWithMemberMissingInBothClasses(x: AWithMethod | BWithMethod) { - if ("c" in x) { - x.a(); - x.b(); - } else { - x.a(); - x.b(); - } -} - -class C { a: string } -class D { a: string } - -function negativeMultipleClassesTest(x: A | B | C | D) { - if ("a" in x) { - x.b = "1"; - } else { - x.a = "1"; - } -} - -class ClassWithProp { prop: A | B } - -function negativePropTest(x: ClassWithProp) { - if ("a" in x.prop) { - let y: string = x.prop.b; - } else { - let z: string = x.prop.a; - } -} - -class NegativeClassTest { - protected prop: A | B; - inThis() { - if ('a' in this.prop) { - let z: number = this.prop.b; - } else { - let y: string = this.prop.a; - } - } -} - -class UnreachableCodeDetection { - a: string; - inThis() { - if ('a' in this) { - } else { - let y = this.a; - } - } +class A { a: string; } +class B { b: string; } + +function negativeClassesTest(x: A | B) { + if ("a" in x) { + x.b = "1"; + } else { + x.a = "1"; + } +} + +function positiveClassesTest(x: A | B) { + if ("a" in x) { + x.b = "1"; + } else { + x.a = "1"; + } +} + +class AWithOptionalProp { a?: string; } +class BWithOptionalProp { b?: string; } + +function positiveTestClassesWithOptionalProperties(x: AWithOptionalProp | BWithOptionalProp) { + if ("a" in x) { + x.a = "1"; + } else { + x.b = "1"; + } +} + +class AWithMethod { + a(): string { return ""; } +} + +class BWithMethod { + b(): string { return ""; } +} + +function negativeTestClassesWithMembers(x: AWithMethod | BWithMethod) { + if ("a" in x) { + x.a(); + x.b(); + } else { + } +} + +function negativeTestClassesWithMemberMissingInBothClasses(x: AWithMethod | BWithMethod) { + if ("c" in x) { + x.a(); + x.b(); + } else { + x.a(); + x.b(); + } +} + +class C { a: string; } +class D { a: string; } + +function negativeMultipleClassesTest(x: A | B | C | D) { + if ("a" in x) { + x.b = "1"; + } else { + x.a = "1"; + } +} + +class ClassWithUnionProp { prop: A | B } + +function negativePropTest(x: ClassWithUnionProp) { + if ("a" in x.prop) { + let y: string = x.prop.b; + } else { + let z: string = x.prop.a; + } +} + +class NegativeClassTest { + protected prop: A | B; + inThis() { + if ("a" in this.prop) { + let z: number = this.prop.b; + } else { + let y: string = this.prop.a; + } + } +} + +class UnreachableCodeDetection { + a: string; + inThis() { + if ("a" in this) { + } else { + let y = this.a; + } + } } \ No newline at end of file diff --git a/tests/cases/conformance/expressions/typeGuards/typeGuardOfFromPropNameInUnionType.ts b/tests/cases/conformance/expressions/typeGuards/typeGuardOfFromPropNameInUnionType.ts index 2a14fd2aea..d89d7b8c4e 100644 --- a/tests/cases/conformance/expressions/typeGuards/typeGuardOfFromPropNameInUnionType.ts +++ b/tests/cases/conformance/expressions/typeGuards/typeGuardOfFromPropNameInUnionType.ts @@ -1,77 +1,91 @@ -class A { a: string; } -class B { b: number; } -class C { b: Object; } -class D { a: Date; } -class ClassWithProp { prop: A | B } -class NestedClassWithProp { outer: ClassWithProp } - -function namedClasses(x: A | B) { - if ("a" in x) { - x.a = "1"; - } else { - x.b = 1; - } -} - -function multipleClasses(x: A | B | C | D) { - if ("a" in x) { - let y: string | Date = x.a; - } else { - let z: number | Object = x.b; - } -} - -function anonymousClasses(x: { a: string; } | { b: number; }) { - if ("a" in x) { - let y: string = x.a; - } else { - let z: number = x.b; - } -} -function inParenthesizedExpression(x: A | B) { - if ("a" in (x)) { - let y: string = x.a; - } else { - let z: number = x.b; - } -} - - -function inProperty(x: ClassWithProp) { - if ("a" in x.prop) { - let y: string = x.prop.a; - } else { - let z: number = x.prop.b; - } -} - - -function innestedProperty(x: NestedClassWithProp) { - if ("a" in x.outer.prop) { - let y: string = x.outer.prop.a; - } else { - let z: number = x.outer.prop.b; - } -} - -class InMemberOfClass { - protected prop: A | B; - inThis() { - if ('a' in this.prop) { - let y: string = this.prop.a; - } else { - let z: number = this.prop.b; - } - } -} - -//added for completeness -class SelfAssert { - a: string; - inThis() { - if ('a' in this) { - let y: string = this.a; - } else { - } - } +class A { a: string; } +class B { b: number; } +class C { b: Object; } +class D { a: Date; } + +function namedClasses(x: A | B) { + if ("a" in x) { + x.a = "1"; + } else { + x.b = 1; + } +} + +function multipleClasses(x: A | B | C | D) { + if ("a" in x) { + let y: string | Date = x.a; + } else { + let z: number | Object = x.b; + } +} + +function anonymousClasses(x: { a: string; } | { b: number; }) { + if ("a" in x) { + let y: string = x.a; + } else { + let z: number = x.b; + } +} + +class AWithOptionalProp { a?: string; } +class BWithOptionalProp { b?: string; } + +function positiveTestClassesWithOptionalProperties(x: AWithOptionalProp | BWithOptionalProp) { + if ("a" in x) { + x.a = "1"; + } else { + const y: string = x instanceof AWithOptionalProp + ? x.a + : x.b + } +} + +function inParenthesizedExpression(x: A | B) { + if ("a" in (x)) { + let y: string = x.a; + } else { + let z: number = x.b; + } +} + +class ClassWithUnionProp { prop: A | B; } + +function inProperty(x: ClassWithUnionProp) { + if ("a" in x.prop) { + let y: string = x.prop.a; + } else { + let z: number = x.prop.b; + } +} + +class NestedClassWithProp { outer: ClassWithUnionProp; } + +function innestedProperty(x: NestedClassWithProp) { + if ("a" in x.outer.prop) { + let y: string = x.outer.prop.a; + } else { + let z: number = x.outer.prop.b; + } +} + +class InMemberOfClass { + protected prop: A | B; + inThis() { + if ("a" in this.prop) { + let y: string = this.prop.a; + } else { + let z: number = this.prop.b; + } + } +} + +// added for completeness +class SelfAssert { + a: string; + inThis() { + if ("a" in this) { + let y: string = this.a; + } else { + } + } } \ No newline at end of file