diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 5215bf063ebf1..a5d94c21e43f8 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -26458,6 +26458,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function isConstantReference(node: Node): boolean { switch (node.kind) { + case SyntaxKind.ThisKeyword: + return true; case SyntaxKind.Identifier: if (!isThisInTypeQuery(node)) { const symbol = getResolvedSymbol(node as Identifier); diff --git a/tests/baselines/reference/controlFlowAliasing.errors.txt b/tests/baselines/reference/controlFlowAliasing.errors.txt index 3bdd7b9a7eec4..0a81bf36bc2f3 100644 --- a/tests/baselines/reference/controlFlowAliasing.errors.txt +++ b/tests/baselines/reference/controlFlowAliasing.errors.txt @@ -22,17 +22,13 @@ tests/cases/conformance/controlFlow/controlFlowAliasing.ts(154,19): error TS2339 Property 'foo' does not exist on type '{ kind: "bar"; bar: number; }'. tests/cases/conformance/controlFlow/controlFlowAliasing.ts(157,19): error TS2339: Property 'bar' does not exist on type '{ kind: "foo"; foo: string; } | { kind: "bar"; bar: number; }'. Property 'bar' does not exist on type '{ kind: "foo"; foo: string; }'. -tests/cases/conformance/controlFlow/controlFlowAliasing.ts(219,13): error TS2322: Type 'string | number' is not assignable to type 'string'. - Type 'number' is not assignable to type 'string'. -tests/cases/conformance/controlFlow/controlFlowAliasing.ts(232,13): error TS2322: Type 'string | number' is not assignable to type 'string'. - Type 'number' is not assignable to type 'string'. tests/cases/conformance/controlFlow/controlFlowAliasing.ts(233,13): error TS2322: Type 'string | number' is not assignable to type 'string'. Type 'number' is not assignable to type 'string'. tests/cases/conformance/controlFlow/controlFlowAliasing.ts(280,5): error TS2448: Block-scoped variable 'a' used before its declaration. tests/cases/conformance/controlFlow/controlFlowAliasing.ts(280,5): error TS2454: Variable 'a' is used before being assigned. -==== tests/cases/conformance/controlFlow/controlFlowAliasing.ts (17 errors) ==== +==== tests/cases/conformance/controlFlow/controlFlowAliasing.ts (15 errors) ==== // Narrowing by aliased conditional expressions function f10(x: string | number) { @@ -288,9 +284,6 @@ tests/cases/conformance/controlFlow/controlFlowAliasing.ts(280,5): error TS2454: if (thisX_isString && xIsString) { let s: string; s = this.x; - ~ -!!! error TS2322: Type 'string | number' is not assignable to type 'string'. -!!! error TS2322: Type 'number' is not assignable to type 'string'. s = x; } } @@ -304,9 +297,6 @@ tests/cases/conformance/controlFlow/controlFlowAliasing.ts(280,5): error TS2454: // Some narrowings may be invalidated due to later assignments. let s: string; s = this.x; - ~ -!!! error TS2322: Type 'string | number' is not assignable to type 'string'. -!!! error TS2322: Type 'number' is not assignable to type 'string'. s = x; ~ !!! error TS2322: Type 'string | number' is not assignable to type 'string'. @@ -365,4 +355,22 @@ tests/cases/conformance/controlFlow/controlFlowAliasing.ts(280,5): error TS2454: !!! error TS2454: Variable 'a' is used before being assigned. const a = obj.fn(); - \ No newline at end of file + + // repro from https://github.com/microsoft/TypeScript/issues/53267 + class Utils { + static isDefined(value: T): value is NonNullable { + return value != null; + } + } + + class A53267 { + public readonly testNumber: number | undefined; + + foo() { + const isNumber = Utils.isDefined(this.testNumber); + + if (isNumber) { + const x: number = this.testNumber; + } + } + } \ No newline at end of file diff --git a/tests/baselines/reference/controlFlowAliasing.js b/tests/baselines/reference/controlFlowAliasing.js index 98d4238286237..20db91b974b20 100644 --- a/tests/baselines/reference/controlFlowAliasing.js +++ b/tests/baselines/reference/controlFlowAliasing.js @@ -281,7 +281,25 @@ const obj = { if (a) { } const a = obj.fn(); - + +// repro from https://github.com/microsoft/TypeScript/issues/53267 +class Utils { + static isDefined(value: T): value is NonNullable { + return value != null; + } +} + +class A53267 { + public readonly testNumber: number | undefined; + + foo() { + const isNumber = Utils.isDefined(this.testNumber); + + if (isNumber) { + const x: number = this.testNumber; + } + } +} //// [controlFlowAliasing.js] "use strict"; @@ -538,6 +556,26 @@ var obj = { }; if (a) { } var a = obj.fn(); +// repro from https://github.com/microsoft/TypeScript/issues/53267 +var Utils = /** @class */ (function () { + function Utils() { + } + Utils.isDefined = function (value) { + return value != null; + }; + return Utils; +}()); +var A53267 = /** @class */ (function () { + function A53267() { + } + A53267.prototype.foo = function () { + var isNumber = Utils.isDefined(this.testNumber); + if (isNumber) { + var x = this.testNumber; + } + }; + return A53267; +}()); //// [controlFlowAliasing.d.ts] @@ -677,3 +715,10 @@ declare const obj: { fn: () => boolean; }; declare const a: boolean; +declare class Utils { + static isDefined(value: T): value is NonNullable; +} +declare class A53267 { + readonly testNumber: number | undefined; + foo(): void; +} diff --git a/tests/baselines/reference/controlFlowAliasing.symbols b/tests/baselines/reference/controlFlowAliasing.symbols index 5fde002caff5c..f6a255579832a 100644 --- a/tests/baselines/reference/controlFlowAliasing.symbols +++ b/tests/baselines/reference/controlFlowAliasing.symbols @@ -791,3 +791,50 @@ const a = obj.fn(); >obj : Symbol(obj, Decl(controlFlowAliasing.ts, 275, 5)) >fn : Symbol(fn, Decl(controlFlowAliasing.ts, 275, 13)) +// repro from https://github.com/microsoft/TypeScript/issues/53267 +class Utils { +>Utils : Symbol(Utils, Decl(controlFlowAliasing.ts, 281, 19)) + + static isDefined(value: T): value is NonNullable { +>isDefined : Symbol(Utils.isDefined, Decl(controlFlowAliasing.ts, 284, 13)) +>T : Symbol(T, Decl(controlFlowAliasing.ts, 285, 19)) +>value : Symbol(value, Decl(controlFlowAliasing.ts, 285, 22)) +>T : Symbol(T, Decl(controlFlowAliasing.ts, 285, 19)) +>value : Symbol(value, Decl(controlFlowAliasing.ts, 285, 22)) +>NonNullable : Symbol(NonNullable, Decl(lib.es5.d.ts, --, --)) +>T : Symbol(T, Decl(controlFlowAliasing.ts, 285, 19)) + + return value != null; +>value : Symbol(value, Decl(controlFlowAliasing.ts, 285, 22)) + } +} + +class A53267 { +>A53267 : Symbol(A53267, Decl(controlFlowAliasing.ts, 288, 1)) + + public readonly testNumber: number | undefined; +>testNumber : Symbol(A53267.testNumber, Decl(controlFlowAliasing.ts, 290, 14)) + + foo() { +>foo : Symbol(A53267.foo, Decl(controlFlowAliasing.ts, 291, 49)) + + const isNumber = Utils.isDefined(this.testNumber); +>isNumber : Symbol(isNumber, Decl(controlFlowAliasing.ts, 294, 9)) +>Utils.isDefined : Symbol(Utils.isDefined, Decl(controlFlowAliasing.ts, 284, 13)) +>Utils : Symbol(Utils, Decl(controlFlowAliasing.ts, 281, 19)) +>isDefined : Symbol(Utils.isDefined, Decl(controlFlowAliasing.ts, 284, 13)) +>this.testNumber : Symbol(A53267.testNumber, Decl(controlFlowAliasing.ts, 290, 14)) +>this : Symbol(A53267, Decl(controlFlowAliasing.ts, 288, 1)) +>testNumber : Symbol(A53267.testNumber, Decl(controlFlowAliasing.ts, 290, 14)) + + if (isNumber) { +>isNumber : Symbol(isNumber, Decl(controlFlowAliasing.ts, 294, 9)) + + const x: number = this.testNumber; +>x : Symbol(x, Decl(controlFlowAliasing.ts, 297, 11)) +>this.testNumber : Symbol(A53267.testNumber, Decl(controlFlowAliasing.ts, 290, 14)) +>this : Symbol(A53267, Decl(controlFlowAliasing.ts, 288, 1)) +>testNumber : Symbol(A53267.testNumber, Decl(controlFlowAliasing.ts, 290, 14)) + } + } +} diff --git a/tests/baselines/reference/controlFlowAliasing.types b/tests/baselines/reference/controlFlowAliasing.types index 92faf393b0dcd..bda9874483e5c 100644 --- a/tests/baselines/reference/controlFlowAliasing.types +++ b/tests/baselines/reference/controlFlowAliasing.types @@ -731,11 +731,11 @@ class C10 { >s : string s = this.x; ->s = this.x : string | number +>s = this.x : string >s : string ->this.x : string | number +>this.x : string >this : this ->x : string | number +>x : string s = x; >s = x : string @@ -777,11 +777,11 @@ class C11 { >s : string s = this.x; ->s = this.x : string | number +>s = this.x : string >s : string ->this.x : string | number +>this.x : string >this : this ->x : string | number +>x : string s = x; >s = x : string | number @@ -918,3 +918,47 @@ const a = obj.fn(); >obj : { fn: () => boolean; } >fn : () => boolean +// repro from https://github.com/microsoft/TypeScript/issues/53267 +class Utils { +>Utils : Utils + + static isDefined(value: T): value is NonNullable { +>isDefined : (value: T) => value is NonNullable +>value : T + + return value != null; +>value != null : boolean +>value : T + } +} + +class A53267 { +>A53267 : A53267 + + public readonly testNumber: number | undefined; +>testNumber : number | undefined + + foo() { +>foo : () => void + + const isNumber = Utils.isDefined(this.testNumber); +>isNumber : boolean +>Utils.isDefined(this.testNumber) : boolean +>Utils.isDefined : (value: T) => value is NonNullable +>Utils : typeof Utils +>isDefined : (value: T) => value is NonNullable +>this.testNumber : number | undefined +>this : this +>testNumber : number | undefined + + if (isNumber) { +>isNumber : boolean + + const x: number = this.testNumber; +>x : number +>this.testNumber : number +>this : this +>testNumber : number + } + } +} diff --git a/tests/cases/conformance/controlFlow/controlFlowAliasing.ts b/tests/cases/conformance/controlFlow/controlFlowAliasing.ts index 03b7530921d91..b32f80abae94f 100644 --- a/tests/cases/conformance/controlFlow/controlFlowAliasing.ts +++ b/tests/cases/conformance/controlFlow/controlFlowAliasing.ts @@ -283,3 +283,22 @@ const obj = { if (a) { } const a = obj.fn(); + +// repro from https://github.com/microsoft/TypeScript/issues/53267 +class Utils { + static isDefined(value: T): value is NonNullable { + return value != null; + } +} + +class A53267 { + public readonly testNumber: number | undefined; + + foo() { + const isNumber = Utils.isDefined(this.testNumber); + + if (isNumber) { + const x: number = this.testNumber; + } + } +} \ No newline at end of file