Merge pull request #15256 from IdeaHunter/in-typeguard

Add type guard for `in` keyword
This commit is contained in:
Ryan Cavanaugh
2017-12-06 10:32:07 -08:00
committed by GitHub
14 changed files with 2000 additions and 8 deletions

View File

@@ -749,6 +749,10 @@ namespace ts {
return expr1.kind === SyntaxKind.TypeOfExpression && isNarrowableOperand((<TypeOfExpression>expr1).expression) && expr2.kind === SyntaxKind.StringLiteral;
}
function isNarrowableInOperands(left: Expression, right: Expression) {
return left.kind === SyntaxKind.StringLiteral && isNarrowingExpression(right);
}
function isNarrowingBinaryExpression(expr: BinaryExpression) {
switch (expr.operatorToken.kind) {
case SyntaxKind.EqualsToken:
@@ -761,6 +765,8 @@ namespace ts {
isNarrowingTypeofOperands(expr.right, expr.left) || isNarrowingTypeofOperands(expr.left, expr.right);
case SyntaxKind.InstanceOfKeyword:
return isNarrowableOperand(expr.left);
case SyntaxKind.InKeyword:
return isNarrowableInOperands(expr.left, expr.right);
case SyntaxKind.CommaToken:
return isNarrowingExpression(expr.right);
}

View File

@@ -12722,6 +12722,22 @@ namespace ts {
return type;
}
function isTypePresencePossible(type: Type, propName: __String, assumeTrue: boolean) {
const prop = getPropertyOfType(type, propName);
if (prop) {
return (prop.flags & SymbolFlags.Optional) ? true : assumeTrue;
}
return !assumeTrue;
}
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 = escapeLeadingUnderscores(literal.text);
return filterType(type, t => isTypePresencePossible(t, propName, /* assumeTrue */ assumeTrue));
}
return type;
}
function narrowTypeByBinaryExpression(type: Type, expr: BinaryExpression, assumeTrue: boolean): Type {
switch (expr.operatorToken.kind) {
case SyntaxKind.EqualsToken:
@@ -12757,6 +12773,12 @@ namespace ts {
break;
case SyntaxKind.InstanceOfKeyword:
return narrowTypeByInstanceof(type, expr, assumeTrue);
case SyntaxKind.InKeyword:
const target = getReferenceCandidate(expr.right);
if (expr.left.kind === SyntaxKind.StringLiteral && isMatchingReference(reference, target)) {
return narrowByInKeyword(type, <LiteralExpression>expr.left, assumeTrue);
}
break;
case SyntaxKind.CommaToken:
return narrowType(type, expr.right, assumeTrue);
}

View File

@@ -3,6 +3,7 @@ tests/cases/conformance/fixSignatureCaching.ts(284,10): error TS2339: Property '
tests/cases/conformance/fixSignatureCaching.ts(293,10): error TS2339: Property 'FALLBACK_PHONE' does not exist on type '{}'.
tests/cases/conformance/fixSignatureCaching.ts(294,10): error TS2339: Property 'FALLBACK_TABLET' does not exist on type '{}'.
tests/cases/conformance/fixSignatureCaching.ts(295,10): error TS2339: Property 'FALLBACK_MOBILE' does not exist on type '{}'.
tests/cases/conformance/fixSignatureCaching.ts(301,17): error TS2339: Property 'isArray' does not exist on type 'never'.
tests/cases/conformance/fixSignatureCaching.ts(330,74): error TS2339: Property 'mobileDetectRules' does not exist on type '{}'.
tests/cases/conformance/fixSignatureCaching.ts(369,10): error TS2339: Property 'findMatch' does not exist on type '{}'.
tests/cases/conformance/fixSignatureCaching.ts(387,10): error TS2339: Property 'findMatches' does not exist on type '{}'.
@@ -71,7 +72,7 @@ tests/cases/conformance/fixSignatureCaching.ts(982,23): error TS2304: Cannot fin
tests/cases/conformance/fixSignatureCaching.ts(983,37): error TS2304: Cannot find name 'window'.
==== tests/cases/conformance/fixSignatureCaching.ts (71 errors) ====
==== tests/cases/conformance/fixSignatureCaching.ts (72 errors) ====
// Repro from #10697
(function (define, undefined) {
@@ -383,6 +384,8 @@ tests/cases/conformance/fixSignatureCaching.ts(983,37): error TS2304: Cannot fin
isArray = 'isArray' in Array
? function (value) { return Object.prototype.toString.call(value) === '[object Array]'; }
: Array.isArray;
~~~~~~~
!!! error TS2339: Property 'isArray' does not exist on type 'never'.
function equalIC(a, b) {
return a != null && b != null && a.toLowerCase() === b.toLowerCase();

View File

@@ -358,9 +358,7 @@ define(function () {
>value : Symbol(value, Decl(fixSignatureCaching.ts, 299, 20))
: Array.isArray;
>Array.isArray : Symbol(ArrayConstructor.isArray, Decl(lib.d.ts, --, --))
>Array : Symbol(Array, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
>isArray : Symbol(ArrayConstructor.isArray, Decl(lib.d.ts, --, --))
function equalIC(a, b) {
>equalIC : Symbol(equalIC, Decl(fixSignatureCaching.ts, 300, 24))

View File

@@ -893,9 +893,9 @@ define(function () {
>'[object Array]' : "[object Array]"
isArray = 'isArray' in Array
>isArray = 'isArray' in Array ? function (value) { return Object.prototype.toString.call(value) === '[object Array]'; } : Array.isArray : (value: any) => boolean
>isArray = 'isArray' in Array ? function (value) { return Object.prototype.toString.call(value) === '[object Array]'; } : Array.isArray : any
>isArray : any
>'isArray' in Array ? function (value) { return Object.prototype.toString.call(value) === '[object Array]'; } : Array.isArray : (value: any) => boolean
>'isArray' in Array ? function (value) { return Object.prototype.toString.call(value) === '[object Array]'; } : Array.isArray : any
>'isArray' in Array : boolean
>'isArray' : "isArray"
>Array : ArrayConstructor
@@ -916,9 +916,9 @@ define(function () {
>'[object Array]' : "[object Array]"
: Array.isArray;
>Array.isArray : (arg: any) => arg is any[]
>Array : ArrayConstructor
>isArray : (arg: any) => arg is any[]
>Array.isArray : any
>Array : never
>isArray : any
function equalIC(a, b) {
>equalIC : (a: any, b: any) => boolean

View File

@@ -0,0 +1,159 @@
tests/cases/compiler/inKeywordTypeguard.ts(6,11): error TS2339: Property 'b' does not exist on type 'A'.
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'.
tests/cases/compiler/inKeywordTypeguard.ts(52,11): error TS2339: Property 'a' does not exist on type 'AWithMethod | BWithMethod'.
Property 'a' does not exist on type 'BWithMethod'.
tests/cases/compiler/inKeywordTypeguard.ts(53,11): error TS2339: Property 'b' does not exist on type 'AWithMethod | BWithMethod'.
Property 'b' does not exist on type 'AWithMethod'.
tests/cases/compiler/inKeywordTypeguard.ts(62,11): error TS2339: Property 'b' does not exist on type 'A | C | D'.
Property 'b' does not exist on type 'A'.
tests/cases/compiler/inKeywordTypeguard.ts(64,11): error TS2339: Property 'a' does not exist on type 'B'.
tests/cases/compiler/inKeywordTypeguard.ts(72,32): error TS2339: Property 'b' does not exist on type 'A'.
tests/cases/compiler/inKeywordTypeguard.ts(74,32): error TS2339: Property 'a' does not exist on type 'B'.
tests/cases/compiler/inKeywordTypeguard.ts(82,39): error TS2339: Property 'b' does not exist on type 'A'.
tests/cases/compiler/inKeywordTypeguard.ts(84,39): error TS2339: Property 'a' does not exist on type 'B'.
tests/cases/compiler/inKeywordTypeguard.ts(94,26): error TS2339: Property 'a' does not exist on type 'never'.
==== tests/cases/compiler/inKeywordTypeguard.ts (17 errors) ====
class A { a: string; }
class B { b: string; }
function negativeClassesTest(x: A | B) {
if ("a" in x) {
x.b = "1";
~
!!! error TS2339: Property 'b' does not exist on type 'A'.
} else {
x.a = "1";
~
!!! error TS2339: Property 'a' does not exist on type 'B'.
}
}
function positiveClassesTest(x: A | B) {
if ("a" in x) {
x.b = "1";
~
!!! error TS2339: Property 'b' does not exist on type 'A'.
} else {
x.a = "1";
~
!!! error TS2339: Property 'a' does not exist on type 'B'.
}
}
class AWithOptionalProp { a?: string; }
class BWithOptionalProp { b?: string; }
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 ""; }
}
class BWithMethod {
b(): string { return ""; }
}
function negativeTestClassesWithMembers(x: AWithMethod | BWithMethod) {
if ("a" in x) {
x.a();
x.b();
~
!!! error TS2339: Property 'b' does not exist on type 'AWithMethod'.
} else {
}
}
function negativeTestClassesWithMemberMissingInBothClasses(x: AWithMethod | BWithMethod) {
if ("c" in x) {
x.a();
~
!!! error TS2339: Property 'a' does not exist on type 'never'.
x.b();
~
!!! error TS2339: Property 'b' does not exist on type 'never'.
} else {
x.a();
~
!!! error TS2339: Property 'a' does not exist on type 'AWithMethod | BWithMethod'.
!!! error TS2339: Property 'a' does not exist on type 'BWithMethod'.
x.b();
~
!!! error TS2339: Property 'b' does not exist on type 'AWithMethod | BWithMethod'.
!!! error TS2339: Property 'b' does not exist on type 'AWithMethod'.
}
}
class C { a: string; }
class D { a: string; }
function negativeMultipleClassesTest(x: A | B | C | D) {
if ("a" in x) {
x.b = "1";
~
!!! error TS2339: Property 'b' does not exist on type 'A | C | D'.
!!! error TS2339: Property 'b' does not exist on type 'A'.
} else {
x.a = "1";
~
!!! error TS2339: Property 'a' does not exist on type 'B'.
}
}
class ClassWithUnionProp { prop: A | B }
function negativePropTest(x: ClassWithUnionProp) {
if ("a" in x.prop) {
let y: string = x.prop.b;
~
!!! error TS2339: Property 'b' does not exist on type 'A'.
} else {
let z: string = x.prop.a;
~
!!! error TS2339: Property 'a' does not exist on type 'B'.
}
}
class NegativeClassTest {
protected prop: A | B;
inThis() {
if ("a" in this.prop) {
let z: number = this.prop.b;
~
!!! error TS2339: Property 'b' does not exist on type 'A'.
} else {
let y: string = this.prop.a;
~
!!! error TS2339: Property 'a' does not exist on type 'B'.
}
}
}
class UnreachableCodeDetection {
a: string;
inThis() {
if ("a" in this) {
} else {
let y = this.a;
~
!!! error TS2339: Property 'a' does not exist on type 'never'.
}
}
}

View File

@@ -0,0 +1,230 @@
//// [inKeywordTypeguard.ts]
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;
}
}
}
//// [inKeywordTypeguard.js]
var A = /** @class */ (function () {
function A() {
}
return A;
}());
var B = /** @class */ (function () {
function B() {
}
return B;
}());
function negativeClassesTest(x) {
if ("a" in x) {
x.b = "1";
}
else {
x.a = "1";
}
}
function positiveClassesTest(x) {
if ("a" in x) {
x.b = "1";
}
else {
x.a = "1";
}
}
var AWithOptionalProp = /** @class */ (function () {
function AWithOptionalProp() {
}
return AWithOptionalProp;
}());
var BWithOptionalProp = /** @class */ (function () {
function BWithOptionalProp() {
}
return BWithOptionalProp;
}());
function positiveTestClassesWithOptionalProperties(x) {
if ("a" in x) {
x.a = "1";
}
else {
x.b = "1";
}
}
var AWithMethod = /** @class */ (function () {
function AWithMethod() {
}
AWithMethod.prototype.a = function () { return ""; };
return AWithMethod;
}());
var BWithMethod = /** @class */ (function () {
function BWithMethod() {
}
BWithMethod.prototype.b = function () { return ""; };
return BWithMethod;
}());
function negativeTestClassesWithMembers(x) {
if ("a" in x) {
x.a();
x.b();
}
else {
}
}
function negativeTestClassesWithMemberMissingInBothClasses(x) {
if ("c" in x) {
x.a();
x.b();
}
else {
x.a();
x.b();
}
}
var C = /** @class */ (function () {
function C() {
}
return C;
}());
var D = /** @class */ (function () {
function D() {
}
return D;
}());
function negativeMultipleClassesTest(x) {
if ("a" in x) {
x.b = "1";
}
else {
x.a = "1";
}
}
var ClassWithUnionProp = /** @class */ (function () {
function ClassWithUnionProp() {
}
return ClassWithUnionProp;
}());
function negativePropTest(x) {
if ("a" in x.prop) {
var y = x.prop.b;
}
else {
var z = x.prop.a;
}
}
var NegativeClassTest = /** @class */ (function () {
function NegativeClassTest() {
}
NegativeClassTest.prototype.inThis = function () {
if ("a" in this.prop) {
var z = this.prop.b;
}
else {
var y = this.prop.a;
}
};
return NegativeClassTest;
}());
var UnreachableCodeDetection = /** @class */ (function () {
function UnreachableCodeDetection() {
}
UnreachableCodeDetection.prototype.inThis = function () {
if ("a" in this) {
}
else {
var y = this.a;
}
};
return UnreachableCodeDetection;
}());

View File

@@ -0,0 +1,241 @@
=== tests/cases/compiler/inKeywordTypeguard.ts ===
class A { a: string; }
>A : Symbol(A, Decl(inKeywordTypeguard.ts, 0, 0))
>a : Symbol(A.a, Decl(inKeywordTypeguard.ts, 0, 9))
class B { b: string; }
>B : Symbol(B, Decl(inKeywordTypeguard.ts, 0, 22))
>b : Symbol(B.b, Decl(inKeywordTypeguard.ts, 1, 9))
function negativeClassesTest(x: A | B) {
>negativeClassesTest : Symbol(negativeClassesTest, Decl(inKeywordTypeguard.ts, 1, 22))
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 3, 29))
>A : Symbol(A, Decl(inKeywordTypeguard.ts, 0, 0))
>B : Symbol(B, Decl(inKeywordTypeguard.ts, 0, 22))
if ("a" in x) {
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 3, 29))
x.b = "1";
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 3, 29))
} else {
x.a = "1";
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 3, 29))
}
}
function positiveClassesTest(x: A | B) {
>positiveClassesTest : Symbol(positiveClassesTest, Decl(inKeywordTypeguard.ts, 9, 1))
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 11, 29))
>A : Symbol(A, Decl(inKeywordTypeguard.ts, 0, 0))
>B : Symbol(B, Decl(inKeywordTypeguard.ts, 0, 22))
if ("a" in x) {
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 11, 29))
x.b = "1";
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 11, 29))
} else {
x.a = "1";
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 11, 29))
}
}
class AWithOptionalProp { a?: string; }
>AWithOptionalProp : Symbol(AWithOptionalProp, Decl(inKeywordTypeguard.ts, 17, 1))
>a : Symbol(AWithOptionalProp.a, Decl(inKeywordTypeguard.ts, 19, 25))
class BWithOptionalProp { b?: string; }
>BWithOptionalProp : Symbol(BWithOptionalProp, Decl(inKeywordTypeguard.ts, 19, 39))
>b : Symbol(BWithOptionalProp.b, Decl(inKeywordTypeguard.ts, 20, 25))
function positiveTestClassesWithOptionalProperties(x: AWithOptionalProp | BWithOptionalProp) {
>positiveTestClassesWithOptionalProperties : Symbol(positiveTestClassesWithOptionalProperties, Decl(inKeywordTypeguard.ts, 20, 39))
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 22, 51))
>AWithOptionalProp : Symbol(AWithOptionalProp, Decl(inKeywordTypeguard.ts, 17, 1))
>BWithOptionalProp : Symbol(BWithOptionalProp, Decl(inKeywordTypeguard.ts, 19, 39))
if ("a" in x) {
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 22, 51))
x.a = "1";
>x.a : Symbol(AWithOptionalProp.a, Decl(inKeywordTypeguard.ts, 19, 25))
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 22, 51))
>a : Symbol(AWithOptionalProp.a, Decl(inKeywordTypeguard.ts, 19, 25))
} else {
x.b = "1";
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 22, 51))
}
}
class AWithMethod {
>AWithMethod : Symbol(AWithMethod, Decl(inKeywordTypeguard.ts, 28, 1))
a(): string { return ""; }
>a : Symbol(AWithMethod.a, Decl(inKeywordTypeguard.ts, 30, 19))
}
class BWithMethod {
>BWithMethod : Symbol(BWithMethod, Decl(inKeywordTypeguard.ts, 32, 1))
b(): string { return ""; }
>b : Symbol(BWithMethod.b, Decl(inKeywordTypeguard.ts, 34, 19))
}
function negativeTestClassesWithMembers(x: AWithMethod | BWithMethod) {
>negativeTestClassesWithMembers : Symbol(negativeTestClassesWithMembers, Decl(inKeywordTypeguard.ts, 36, 1))
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 38, 40))
>AWithMethod : Symbol(AWithMethod, Decl(inKeywordTypeguard.ts, 28, 1))
>BWithMethod : Symbol(BWithMethod, Decl(inKeywordTypeguard.ts, 32, 1))
if ("a" in x) {
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 38, 40))
x.a();
>x.a : Symbol(AWithMethod.a, Decl(inKeywordTypeguard.ts, 30, 19))
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 38, 40))
>a : Symbol(AWithMethod.a, Decl(inKeywordTypeguard.ts, 30, 19))
x.b();
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 38, 40))
} else {
}
}
function negativeTestClassesWithMemberMissingInBothClasses(x: AWithMethod | BWithMethod) {
>negativeTestClassesWithMemberMissingInBothClasses : Symbol(negativeTestClassesWithMemberMissingInBothClasses, Decl(inKeywordTypeguard.ts, 44, 1))
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 46, 59))
>AWithMethod : Symbol(AWithMethod, Decl(inKeywordTypeguard.ts, 28, 1))
>BWithMethod : Symbol(BWithMethod, Decl(inKeywordTypeguard.ts, 32, 1))
if ("c" in x) {
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 46, 59))
x.a();
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 46, 59))
x.b();
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 46, 59))
} else {
x.a();
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 46, 59))
x.b();
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 46, 59))
}
}
class C { a: string; }
>C : Symbol(C, Decl(inKeywordTypeguard.ts, 54, 1))
>a : Symbol(C.a, Decl(inKeywordTypeguard.ts, 56, 9))
class D { a: string; }
>D : Symbol(D, Decl(inKeywordTypeguard.ts, 56, 22))
>a : Symbol(D.a, Decl(inKeywordTypeguard.ts, 57, 9))
function negativeMultipleClassesTest(x: A | B | C | D) {
>negativeMultipleClassesTest : Symbol(negativeMultipleClassesTest, Decl(inKeywordTypeguard.ts, 57, 22))
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 59, 37))
>A : Symbol(A, Decl(inKeywordTypeguard.ts, 0, 0))
>B : Symbol(B, Decl(inKeywordTypeguard.ts, 0, 22))
>C : Symbol(C, Decl(inKeywordTypeguard.ts, 54, 1))
>D : Symbol(D, Decl(inKeywordTypeguard.ts, 56, 22))
if ("a" in x) {
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 59, 37))
x.b = "1";
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 59, 37))
} else {
x.a = "1";
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 59, 37))
}
}
class ClassWithUnionProp { prop: A | B }
>ClassWithUnionProp : Symbol(ClassWithUnionProp, Decl(inKeywordTypeguard.ts, 65, 1))
>prop : Symbol(ClassWithUnionProp.prop, Decl(inKeywordTypeguard.ts, 67, 26))
>A : Symbol(A, Decl(inKeywordTypeguard.ts, 0, 0))
>B : Symbol(B, Decl(inKeywordTypeguard.ts, 0, 22))
function negativePropTest(x: ClassWithUnionProp) {
>negativePropTest : Symbol(negativePropTest, Decl(inKeywordTypeguard.ts, 67, 40))
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 69, 26))
>ClassWithUnionProp : Symbol(ClassWithUnionProp, Decl(inKeywordTypeguard.ts, 65, 1))
if ("a" in x.prop) {
>x.prop : Symbol(ClassWithUnionProp.prop, Decl(inKeywordTypeguard.ts, 67, 26))
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 69, 26))
>prop : Symbol(ClassWithUnionProp.prop, Decl(inKeywordTypeguard.ts, 67, 26))
let y: string = x.prop.b;
>y : Symbol(y, Decl(inKeywordTypeguard.ts, 71, 11))
>x.prop : Symbol(ClassWithUnionProp.prop, Decl(inKeywordTypeguard.ts, 67, 26))
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 69, 26))
>prop : Symbol(ClassWithUnionProp.prop, Decl(inKeywordTypeguard.ts, 67, 26))
} else {
let z: string = x.prop.a;
>z : Symbol(z, Decl(inKeywordTypeguard.ts, 73, 11))
>x.prop : Symbol(ClassWithUnionProp.prop, Decl(inKeywordTypeguard.ts, 67, 26))
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 69, 26))
>prop : Symbol(ClassWithUnionProp.prop, Decl(inKeywordTypeguard.ts, 67, 26))
}
}
class NegativeClassTest {
>NegativeClassTest : Symbol(NegativeClassTest, Decl(inKeywordTypeguard.ts, 75, 1))
protected prop: A | B;
>prop : Symbol(NegativeClassTest.prop, Decl(inKeywordTypeguard.ts, 77, 25))
>A : Symbol(A, Decl(inKeywordTypeguard.ts, 0, 0))
>B : Symbol(B, Decl(inKeywordTypeguard.ts, 0, 22))
inThis() {
>inThis : Symbol(NegativeClassTest.inThis, Decl(inKeywordTypeguard.ts, 78, 26))
if ("a" in this.prop) {
>this.prop : Symbol(NegativeClassTest.prop, Decl(inKeywordTypeguard.ts, 77, 25))
>this : Symbol(NegativeClassTest, Decl(inKeywordTypeguard.ts, 75, 1))
>prop : Symbol(NegativeClassTest.prop, Decl(inKeywordTypeguard.ts, 77, 25))
let z: number = this.prop.b;
>z : Symbol(z, Decl(inKeywordTypeguard.ts, 81, 15))
>this.prop : Symbol(NegativeClassTest.prop, Decl(inKeywordTypeguard.ts, 77, 25))
>this : Symbol(NegativeClassTest, Decl(inKeywordTypeguard.ts, 75, 1))
>prop : Symbol(NegativeClassTest.prop, Decl(inKeywordTypeguard.ts, 77, 25))
} else {
let y: string = this.prop.a;
>y : Symbol(y, Decl(inKeywordTypeguard.ts, 83, 15))
>this.prop : Symbol(NegativeClassTest.prop, Decl(inKeywordTypeguard.ts, 77, 25))
>this : Symbol(NegativeClassTest, Decl(inKeywordTypeguard.ts, 75, 1))
>prop : Symbol(NegativeClassTest.prop, Decl(inKeywordTypeguard.ts, 77, 25))
}
}
}
class UnreachableCodeDetection {
>UnreachableCodeDetection : Symbol(UnreachableCodeDetection, Decl(inKeywordTypeguard.ts, 86, 1))
a: string;
>a : Symbol(UnreachableCodeDetection.a, Decl(inKeywordTypeguard.ts, 88, 32))
inThis() {
>inThis : Symbol(UnreachableCodeDetection.inThis, Decl(inKeywordTypeguard.ts, 89, 14))
if ("a" in this) {
>this : Symbol(UnreachableCodeDetection, Decl(inKeywordTypeguard.ts, 86, 1))
} else {
let y = this.a;
>y : Symbol(y, Decl(inKeywordTypeguard.ts, 93, 15))
}
}
}

View File

@@ -0,0 +1,318 @@
=== tests/cases/compiler/inKeywordTypeguard.ts ===
class A { a: string; }
>A : A
>a : string
class B { b: string; }
>B : B
>b : string
function negativeClassesTest(x: A | B) {
>negativeClassesTest : (x: A | B) => void
>x : A | B
>A : A
>B : B
if ("a" in x) {
>"a" in x : boolean
>"a" : "a"
>x : A | B
x.b = "1";
>x.b = "1" : "1"
>x.b : any
>x : A
>b : any
>"1" : "1"
} else {
x.a = "1";
>x.a = "1" : "1"
>x.a : any
>x : B
>a : any
>"1" : "1"
}
}
function positiveClassesTest(x: A | B) {
>positiveClassesTest : (x: A | B) => void
>x : A | B
>A : A
>B : B
if ("a" in x) {
>"a" in x : boolean
>"a" : "a"
>x : A | B
x.b = "1";
>x.b = "1" : "1"
>x.b : any
>x : A
>b : any
>"1" : "1"
} else {
x.a = "1";
>x.a = "1" : "1"
>x.a : any
>x : B
>a : any
>"1" : "1"
}
}
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 {
x.b = "1";
>x.b = "1" : "1"
>x.b : any
>x : AWithOptionalProp | BWithOptionalProp
>b : any
>"1" : "1"
}
}
class AWithMethod {
>AWithMethod : AWithMethod
a(): string { return ""; }
>a : () => string
>"" : ""
}
class BWithMethod {
>BWithMethod : BWithMethod
b(): string { return ""; }
>b : () => string
>"" : ""
}
function negativeTestClassesWithMembers(x: AWithMethod | BWithMethod) {
>negativeTestClassesWithMembers : (x: AWithMethod | BWithMethod) => void
>x : AWithMethod | BWithMethod
>AWithMethod : AWithMethod
>BWithMethod : BWithMethod
if ("a" in x) {
>"a" in x : boolean
>"a" : "a"
>x : AWithMethod | BWithMethod
x.a();
>x.a() : string
>x.a : () => string
>x : AWithMethod
>a : () => string
x.b();
>x.b() : any
>x.b : any
>x : AWithMethod
>b : any
} else {
}
}
function negativeTestClassesWithMemberMissingInBothClasses(x: AWithMethod | BWithMethod) {
>negativeTestClassesWithMemberMissingInBothClasses : (x: AWithMethod | BWithMethod) => void
>x : AWithMethod | BWithMethod
>AWithMethod : AWithMethod
>BWithMethod : BWithMethod
if ("c" in x) {
>"c" in x : boolean
>"c" : "c"
>x : AWithMethod | BWithMethod
x.a();
>x.a() : any
>x.a : any
>x : never
>a : any
x.b();
>x.b() : any
>x.b : any
>x : never
>b : any
} else {
x.a();
>x.a() : any
>x.a : any
>x : AWithMethod | BWithMethod
>a : any
x.b();
>x.b() : any
>x.b : any
>x : AWithMethod | BWithMethod
>b : any
}
}
class C { a: string; }
>C : C
>a : string
class D { a: string; }
>D : D
>a : string
function negativeMultipleClassesTest(x: A | B | C | D) {
>negativeMultipleClassesTest : (x: A | B | C | D) => void
>x : A | B | C | D
>A : A
>B : B
>C : C
>D : D
if ("a" in x) {
>"a" in x : boolean
>"a" : "a"
>x : A | B | C | D
x.b = "1";
>x.b = "1" : "1"
>x.b : any
>x : A | C | D
>b : any
>"1" : "1"
} else {
x.a = "1";
>x.a = "1" : "1"
>x.a : any
>x : B
>a : any
>"1" : "1"
}
}
class ClassWithUnionProp { prop: A | B }
>ClassWithUnionProp : ClassWithUnionProp
>prop : A | B
>A : A
>B : B
function negativePropTest(x: ClassWithUnionProp) {
>negativePropTest : (x: ClassWithUnionProp) => void
>x : ClassWithUnionProp
>ClassWithUnionProp : ClassWithUnionProp
if ("a" in x.prop) {
>"a" in x.prop : boolean
>"a" : "a"
>x.prop : A | B
>x : ClassWithUnionProp
>prop : A | B
let y: string = x.prop.b;
>y : string
>x.prop.b : any
>x.prop : A
>x : ClassWithUnionProp
>prop : A
>b : any
} else {
let z: string = x.prop.a;
>z : string
>x.prop.a : any
>x.prop : B
>x : ClassWithUnionProp
>prop : B
>a : any
}
}
class NegativeClassTest {
>NegativeClassTest : NegativeClassTest
protected prop: A | B;
>prop : A | B
>A : A
>B : B
inThis() {
>inThis : () => void
if ("a" in this.prop) {
>"a" in this.prop : boolean
>"a" : "a"
>this.prop : A | B
>this : this
>prop : A | B
let z: number = this.prop.b;
>z : number
>this.prop.b : any
>this.prop : A
>this : this
>prop : A
>b : any
} else {
let y: string = this.prop.a;
>y : string
>this.prop.a : any
>this.prop : B
>this : this
>prop : B
>a : any
}
}
}
class UnreachableCodeDetection {
>UnreachableCodeDetection : UnreachableCodeDetection
a: string;
>a : string
inThis() {
>inThis : () => void
if ("a" in this) {
>"a" in this : boolean
>"a" : "a"
>this : this
} else {
let y = this.a;
>y : any
>this.a : any
>this : never
>a : any
}
}
}

View File

@@ -0,0 +1,218 @@
//// [typeGuardOfFromPropNameInUnionType.ts]
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 {
}
}
}
//// [typeGuardOfFromPropNameInUnionType.js]
var A = /** @class */ (function () {
function A() {
}
return A;
}());
var B = /** @class */ (function () {
function B() {
}
return B;
}());
var C = /** @class */ (function () {
function C() {
}
return C;
}());
var D = /** @class */ (function () {
function D() {
}
return D;
}());
function namedClasses(x) {
if ("a" in x) {
x.a = "1";
}
else {
x.b = 1;
}
}
function multipleClasses(x) {
if ("a" in x) {
var y = x.a;
}
else {
var z = x.b;
}
}
function anonymousClasses(x) {
if ("a" in x) {
var y = x.a;
}
else {
var z = x.b;
}
}
var AWithOptionalProp = /** @class */ (function () {
function AWithOptionalProp() {
}
return AWithOptionalProp;
}());
var BWithOptionalProp = /** @class */ (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;
}
else {
var z = x.b;
}
}
var ClassWithUnionProp = /** @class */ (function () {
function ClassWithUnionProp() {
}
return ClassWithUnionProp;
}());
function inProperty(x) {
if ("a" in x.prop) {
var y = x.prop.a;
}
else {
var z = x.prop.b;
}
}
var NestedClassWithProp = /** @class */ (function () {
function NestedClassWithProp() {
}
return NestedClassWithProp;
}());
function innestedProperty(x) {
if ("a" in x.outer.prop) {
var y = x.outer.prop.a;
}
else {
var z = x.outer.prop.b;
}
}
var InMemberOfClass = /** @class */ (function () {
function InMemberOfClass() {
}
InMemberOfClass.prototype.inThis = function () {
if ("a" in this.prop) {
var y = this.prop.a;
}
else {
var z = this.prop.b;
}
};
return InMemberOfClass;
}());
// added for completeness
var SelfAssert = /** @class */ (function () {
function SelfAssert() {
}
SelfAssert.prototype.inThis = function () {
if ("a" in this) {
var y = this.a;
}
else {
}
};
return SelfAssert;
}());

View File

@@ -0,0 +1,291 @@
=== tests/cases/conformance/expressions/typeGuards/typeGuardOfFromPropNameInUnionType.ts ===
class A { a: string; }
>A : Symbol(A, Decl(typeGuardOfFromPropNameInUnionType.ts, 0, 0))
>a : Symbol(A.a, Decl(typeGuardOfFromPropNameInUnionType.ts, 0, 9))
class B { b: number; }
>B : Symbol(B, Decl(typeGuardOfFromPropNameInUnionType.ts, 0, 22))
>b : Symbol(B.b, Decl(typeGuardOfFromPropNameInUnionType.ts, 1, 9))
class C { b: Object; }
>C : Symbol(C, Decl(typeGuardOfFromPropNameInUnionType.ts, 1, 22))
>b : Symbol(C.b, Decl(typeGuardOfFromPropNameInUnionType.ts, 2, 9))
>Object : Symbol(Object, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
class D { a: Date; }
>D : Symbol(D, Decl(typeGuardOfFromPropNameInUnionType.ts, 2, 22))
>a : Symbol(D.a, Decl(typeGuardOfFromPropNameInUnionType.ts, 3, 9))
>Date : Symbol(Date, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
function namedClasses(x: A | B) {
>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, 5, 22))
x.a = "1";
>x.a : Symbol(A.a, Decl(typeGuardOfFromPropNameInUnionType.ts, 0, 9))
>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, 5, 22))
>b : Symbol(B.b, Decl(typeGuardOfFromPropNameInUnionType.ts, 1, 9))
}
}
function multipleClasses(x: A | B | C | D) {
>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, 13, 25))
let y: string | Date = x.a;
>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, 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, 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, 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, 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, 21, 26))
let y: string = x.a;
>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, 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, 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, 42, 35))
let y: string = x.a;
>y : Symbol(y, Decl(typeGuardOfFromPropNameInUnionType.ts, 44, 11))
>x.a : Symbol(A.a, Decl(typeGuardOfFromPropNameInUnionType.ts, 0, 9))
>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, 46, 11))
>x.b : Symbol(B.b, Decl(typeGuardOfFromPropNameInUnionType.ts, 1, 9))
>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: 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(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, 54, 11))
>x.prop.a : Symbol(A.a, Decl(typeGuardOfFromPropNameInUnionType.ts, 0, 9))
>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, 56, 11))
>x.prop.b : Symbol(B.b, Decl(typeGuardOfFromPropNameInUnionType.ts, 1, 9))
>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, 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(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, 64, 11))
>x.outer.prop.a : Symbol(A.a, Decl(typeGuardOfFromPropNameInUnionType.ts, 0, 9))
>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, 66, 11))
>x.outer.prop.b : Symbol(B.b, Decl(typeGuardOfFromPropNameInUnionType.ts, 1, 9))
>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, 68, 1))
protected prop: A | B;
>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, 71, 26))
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, 74, 15))
>this.prop.a : Symbol(A.a, Decl(typeGuardOfFromPropNameInUnionType.ts, 0, 9))
>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, 76, 15))
>this.prop.b : Symbol(B.b, Decl(typeGuardOfFromPropNameInUnionType.ts, 1, 9))
>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
class SelfAssert {
>SelfAssert : Symbol(SelfAssert, Decl(typeGuardOfFromPropNameInUnionType.ts, 79, 1))
a: string;
>a : Symbol(SelfAssert.a, Decl(typeGuardOfFromPropNameInUnionType.ts, 82, 18))
inThis() {
>inThis : Symbol(SelfAssert.inThis, Decl(typeGuardOfFromPropNameInUnionType.ts, 83, 14))
if ("a" in this) {
>this : Symbol(SelfAssert, Decl(typeGuardOfFromPropNameInUnionType.ts, 79, 1))
let y: string = this.a;
>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 {
}
}
}

View File

@@ -0,0 +1,318 @@
=== tests/cases/conformance/expressions/typeGuards/typeGuardOfFromPropNameInUnionType.ts ===
class A { a: string; }
>A : A
>a : string
class B { b: number; }
>B : B
>b : number
class C { b: Object; }
>C : C
>b : Object
>Object : Object
class D { a: Date; }
>D : D
>a : Date
>Date : Date
function namedClasses(x: A | B) {
>namedClasses : (x: A | B) => void
>x : A | B
>A : A
>B : B
if ("a" in x) {
>"a" in x : boolean
>"a" : "a"
>x : A | B
x.a = "1";
>x.a = "1" : "1"
>x.a : string
>x : A
>a : string
>"1" : "1"
} else {
x.b = 1;
>x.b = 1 : 1
>x.b : number
>x : B
>b : number
>1 : 1
}
}
function multipleClasses(x: A | B | C | D) {
>multipleClasses : (x: A | B | C | D) => void
>x : A | B | C | D
>A : A
>B : B
>C : C
>D : D
if ("a" in x) {
>"a" in x : boolean
>"a" : "a"
>x : A | B | C | D
let y: string | Date = x.a;
>y : string | Date
>Date : Date
>x.a : string | Date
>x : A | D
>a : string | Date
} else {
let z: number | Object = x.b;
>z : number | Object
>Object : Object
>x.b : number | Object
>x : B | C
>b : number | Object
}
}
function anonymousClasses(x: { a: string; } | { b: number; }) {
>anonymousClasses : (x: { a: string; } | { b: number; }) => void
>x : { a: string; } | { b: number; }
>a : string
>b : number
if ("a" in x) {
>"a" in x : boolean
>"a" : "a"
>x : { a: string; } | { b: number; }
let y: string = x.a;
>y : string
>x.a : string
>x : { a: string; }
>a : string
} else {
let z: number = x.b;
>z : number
>x.b : number
>x : { 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
>A : A
>B : B
if ("a" in (x)) {
>"a" in (x) : boolean
>"a" : "a"
>(x) : A | B
>x : A | B
let y: string = x.a;
>y : string
>x.a : string
>x : A
>a : string
} else {
let z: number = x.b;
>z : number
>x.b : number
>x : B
>b : number
}
}
class ClassWithUnionProp { prop: A | B; }
>ClassWithUnionProp : ClassWithUnionProp
>prop : A | B
>A : A
>B : B
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 : ClassWithUnionProp
>prop : A | B
let y: string = x.prop.a;
>y : string
>x.prop.a : string
>x.prop : A
>x : ClassWithUnionProp
>prop : A
>a : string
} else {
let z: number = x.prop.b;
>z : number
>x.prop.b : number
>x.prop : B
>x : ClassWithUnionProp
>prop : B
>b : number
}
}
class NestedClassWithProp { outer: ClassWithUnionProp; }
>NestedClassWithProp : NestedClassWithProp
>outer : ClassWithUnionProp
>ClassWithUnionProp : ClassWithUnionProp
function innestedProperty(x: NestedClassWithProp) {
>innestedProperty : (x: NestedClassWithProp) => void
>x : NestedClassWithProp
>NestedClassWithProp : NestedClassWithProp
if ("a" in x.outer.prop) {
>"a" in x.outer.prop : boolean
>"a" : "a"
>x.outer.prop : A | B
>x.outer : ClassWithUnionProp
>x : NestedClassWithProp
>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 : ClassWithUnionProp
>x : NestedClassWithProp
>outer : ClassWithUnionProp
>prop : A
>a : string
} else {
let z: number = x.outer.prop.b;
>z : number
>x.outer.prop.b : number
>x.outer.prop : B
>x.outer : ClassWithUnionProp
>x : NestedClassWithProp
>outer : ClassWithUnionProp
>prop : B
>b : number
}
}
class InMemberOfClass {
>InMemberOfClass : InMemberOfClass
protected prop: A | B;
>prop : A | B
>A : A
>B : B
inThis() {
>inThis : () => void
if ("a" in this.prop) {
>"a" in this.prop : boolean
>"a" : "a"
>this.prop : A | B
>this : this
>prop : A | B
let y: string = this.prop.a;
>y : string
>this.prop.a : string
>this.prop : A
>this : this
>prop : A
>a : string
} else {
let z: number = this.prop.b;
>z : number
>this.prop.b : number
>this.prop : B
>this : this
>prop : B
>b : number
}
}
}
// added for completeness
class SelfAssert {
>SelfAssert : SelfAssert
a: string;
>a : string
inThis() {
>inThis : () => void
if ("a" in this) {
>"a" in this : boolean
>"a" : "a"
>this : this
let y: string = this.a;
>y : string
>this.a : string
>this : this
>a : string
} else {
}
}
}

View File

@@ -0,0 +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 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;
}
}
}

View File

@@ -0,0 +1,91 @@
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 {
}
}
}