allow this in typeQuery (#43898)

* allow `this` in typeQuery

* add tests

* get this type as expression

* handle nested nodes

* update baselines
This commit is contained in:
Zzzen
2021-06-17 22:52:20 +08:00
committed by GitHub
parent d46d82c9bd
commit 8dbb2cd5fb
17 changed files with 1282 additions and 21 deletions
+11 -6
View File
@@ -13197,7 +13197,8 @@ namespace ts {
// The expression is processed as an identifier expression (section 4.3)
// or property access expression(section 4.10),
// the widened type(section 3.9) of which becomes the result.
links.resolvedType = getRegularTypeOfLiteralType(getWidenedType(checkExpression(node.exprName)));
const type = isThisIdentifier(node.exprName) ? checkThisExpression(node.exprName) : checkExpression(node.exprName);
links.resolvedType = getRegularTypeOfLiteralType(getWidenedType(type));
}
return links.resolvedType;
}
@@ -21998,9 +21999,11 @@ namespace ts {
&& (source as MetaProperty).name.escapedText === (target as MetaProperty).name.escapedText;
case SyntaxKind.Identifier:
case SyntaxKind.PrivateIdentifier:
return target.kind === SyntaxKind.Identifier && getResolvedSymbol(source as Identifier) === getResolvedSymbol(target as Identifier) ||
(target.kind === SyntaxKind.VariableDeclaration || target.kind === SyntaxKind.BindingElement) &&
getExportSymbolOfValueSymbolIfExported(getResolvedSymbol(source as Identifier)) === getSymbolOfNode(target);
return isThisInTypeQuery(source) ?
target.kind === SyntaxKind.ThisKeyword :
target.kind === SyntaxKind.Identifier && getResolvedSymbol(source as Identifier) === getResolvedSymbol(target as Identifier) ||
(target.kind === SyntaxKind.VariableDeclaration || target.kind === SyntaxKind.BindingElement) &&
getExportSymbolOfValueSymbolIfExported(getResolvedSymbol(source as Identifier)) === getSymbolOfNode(target);
case SyntaxKind.ThisKeyword:
return target.kind === SyntaxKind.ThisKeyword;
case SyntaxKind.SuperKeyword:
@@ -24538,6 +24541,7 @@ namespace ts {
}
function checkThisExpression(node: Node): Type {
const isNodeInTypeQuery = isInTypeQuery(node);
// Stop at the first arrow function so that we can
// tell whether 'this' needs to be captured.
let container = getThisContainer(node, /* includeArrowFunctions */ true);
@@ -24581,7 +24585,7 @@ namespace ts {
}
// When targeting es6, mark that we'll need to capture `this` in its lexically bound scope.
if (capturedByArrowFunction && languageVersion < ScriptTarget.ES2015) {
if (!isNodeInTypeQuery && capturedByArrowFunction && languageVersion < ScriptTarget.ES2015) {
captureLexicalThis(node, container);
}
@@ -27284,7 +27288,8 @@ namespace ts {
}
function checkQualifiedName(node: QualifiedName, checkMode: CheckMode | undefined) {
return checkPropertyAccessExpressionOrQualifiedName(node, node.left, checkNonNullExpression(node.left), node.right, checkMode);
const leftType = isPartOfTypeQuery(node) && isThisIdentifier(node.left) ? checkNonNullType(checkThisExpression(node.left), node.left) : checkNonNullExpression(node.left);
return checkPropertyAccessExpressionOrQualifiedName(node, node.left, leftType, node.right, checkMode);
}
function isMethodAccessForCall(node: Node) {
+12
View File
@@ -4348,6 +4348,18 @@ namespace ts {
return !!node && node.kind === SyntaxKind.Identifier && identifierIsThisKeyword(node as Identifier);
}
export function isThisInTypeQuery(node: Node): boolean {
if (!isThisIdentifier(node)) {
return false;
}
while (isQualifiedName(node.parent) && node.parent.left === node) {
node = node.parent;
}
return node.parent.kind === SyntaxKind.TypeQuery;
}
export function identifierIsThisKeyword(id: Identifier): boolean {
return id.originalKeywordKind === SyntaxKind.ThisKeyword;
}
@@ -1,12 +1,12 @@
tests/cases/conformance/classes/propertyMemberDeclarations/initializerReferencingConstructorLocals.ts(4,9): error TS2304: Cannot find name 'z'.
tests/cases/conformance/classes/propertyMemberDeclarations/initializerReferencingConstructorLocals.ts(5,15): error TS2304: Cannot find name 'z'.
tests/cases/conformance/classes/propertyMemberDeclarations/initializerReferencingConstructorLocals.ts(6,14): error TS2339: Property 'z' does not exist on type 'C'.
tests/cases/conformance/classes/propertyMemberDeclarations/initializerReferencingConstructorLocals.ts(7,15): error TS2304: Cannot find name 'this'.
tests/cases/conformance/classes/propertyMemberDeclarations/initializerReferencingConstructorLocals.ts(7,20): error TS2339: Property 'z' does not exist on type 'C'.
tests/cases/conformance/classes/propertyMemberDeclarations/initializerReferencingConstructorLocals.ts(9,9): error TS2304: Cannot find name 'z'.
tests/cases/conformance/classes/propertyMemberDeclarations/initializerReferencingConstructorLocals.ts(14,9): error TS2304: Cannot find name 'z'.
tests/cases/conformance/classes/propertyMemberDeclarations/initializerReferencingConstructorLocals.ts(15,15): error TS2304: Cannot find name 'z'.
tests/cases/conformance/classes/propertyMemberDeclarations/initializerReferencingConstructorLocals.ts(16,14): error TS2339: Property 'z' does not exist on type 'D<T>'.
tests/cases/conformance/classes/propertyMemberDeclarations/initializerReferencingConstructorLocals.ts(17,15): error TS2304: Cannot find name 'this'.
tests/cases/conformance/classes/propertyMemberDeclarations/initializerReferencingConstructorLocals.ts(17,20): error TS2339: Property 'z' does not exist on type 'D<T>'.
tests/cases/conformance/classes/propertyMemberDeclarations/initializerReferencingConstructorLocals.ts(19,9): error TS2304: Cannot find name 'z'.
@@ -24,8 +24,8 @@ tests/cases/conformance/classes/propertyMemberDeclarations/initializerReferencin
~
!!! error TS2339: Property 'z' does not exist on type 'C'.
d: typeof this.z; // error
~~~~
!!! error TS2304: Cannot find name 'this'.
~
!!! error TS2339: Property 'z' does not exist on type 'C'.
constructor(x) {
z = 1;
~
@@ -44,8 +44,8 @@ tests/cases/conformance/classes/propertyMemberDeclarations/initializerReferencin
~
!!! error TS2339: Property 'z' does not exist on type 'D<T>'.
d: typeof this.z; // error
~~~~
!!! error TS2304: Cannot find name 'this'.
~
!!! error TS2339: Property 'z' does not exist on type 'D<T>'.
constructor(x: T) {
z = 1;
~
@@ -2,11 +2,10 @@ tests/cases/conformance/classes/propertyMemberDeclarations/initializerReferencin
tests/cases/conformance/classes/propertyMemberDeclarations/initializerReferencingConstructorParameters.ts(5,15): error TS2304: Cannot find name 'x'.
tests/cases/conformance/classes/propertyMemberDeclarations/initializerReferencingConstructorParameters.ts(10,9): error TS2663: Cannot find name 'x'. Did you mean the instance member 'this.x'?
tests/cases/conformance/classes/propertyMemberDeclarations/initializerReferencingConstructorParameters.ts(11,15): error TS2304: Cannot find name 'x'.
tests/cases/conformance/classes/propertyMemberDeclarations/initializerReferencingConstructorParameters.ts(17,15): error TS2304: Cannot find name 'this'.
tests/cases/conformance/classes/propertyMemberDeclarations/initializerReferencingConstructorParameters.ts(23,9): error TS2663: Cannot find name 'x'. Did you mean the instance member 'this.x'?
==== tests/cases/conformance/classes/propertyMemberDeclarations/initializerReferencingConstructorParameters.ts (6 errors) ====
==== tests/cases/conformance/classes/propertyMemberDeclarations/initializerReferencingConstructorParameters.ts (5 errors) ====
// Initializer expressions for instance member variables are evaluated in the scope of the class constructor body but are not permitted to reference parameters or local variables of the constructor.
class C {
@@ -31,9 +30,7 @@ tests/cases/conformance/classes/propertyMemberDeclarations/initializerReferencin
class E {
a = this.x; // ok
b: typeof this.x; // error
~~~~
!!! error TS2304: Cannot find name 'this'.
b: typeof this.x; // ok
constructor(public x) { }
}
@@ -15,7 +15,7 @@ class D {
class E {
a = this.x; // ok
b: typeof this.x; // error
b: typeof this.x; // ok
constructor(public x) { }
}
@@ -36,8 +36,10 @@ class E {
>this : Symbol(E, Decl(initializerReferencingConstructorParameters.ts, 12, 1))
>x : Symbol(E.x, Decl(initializerReferencingConstructorParameters.ts, 17, 16))
b: typeof this.x; // error
b: typeof this.x; // ok
>b : Symbol(E.b, Decl(initializerReferencingConstructorParameters.ts, 15, 15))
>this.x : Symbol(E.x, Decl(initializerReferencingConstructorParameters.ts, 17, 16))
>x : Symbol(E.x, Decl(initializerReferencingConstructorParameters.ts, 17, 16))
constructor(public x) { }
>x : Symbol(E.x, Decl(initializerReferencingConstructorParameters.ts, 17, 16))
@@ -40,7 +40,7 @@ class E {
>this : this
>x : any
b: typeof this.x; // error
b: typeof this.x; // ok
>b : any
>this.x : any
>this : any
@@ -0,0 +1,149 @@
tests/cases/conformance/types/specifyingTypes/typeQueries/typeofThis.ts(24,19): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation.
tests/cases/conformance/types/specifyingTypes/typeQueries/typeofThis.ts(32,19): error TS2532: Object is possibly 'undefined'.
tests/cases/conformance/types/specifyingTypes/typeQueries/typeofThis.ts(46,23): error TS2331: 'this' cannot be referenced in a module or namespace body.
tests/cases/conformance/types/specifyingTypes/typeQueries/typeofThis.ts(46,23): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation.
tests/cases/conformance/types/specifyingTypes/typeQueries/typeofThis.ts(52,23): error TS2331: 'this' cannot be referenced in a module or namespace body.
tests/cases/conformance/types/specifyingTypes/typeQueries/typeofThis.ts(52,23): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation.
tests/cases/conformance/types/specifyingTypes/typeQueries/typeofThis.ts(57,19): error TS7041: The containing arrow function captures the global value of 'this'.
tests/cases/conformance/types/specifyingTypes/typeQueries/typeofThis.ts(57,24): error TS7017: Element implicitly has an 'any' type because type 'typeof globalThis' has no index signature.
==== tests/cases/conformance/types/specifyingTypes/typeQueries/typeofThis.ts (8 errors) ====
class Test {
data = {};
constructor() {
var copy: typeof this.data = {};
}
}
class Test1 {
data = { foo: '' };
['this'] = '';
constructor() {
var copy: typeof this.data = { foo: '' };
var foo: typeof this.data.foo = '';
var self: typeof this = this;
self.data;
var str: typeof this.this = '';
}
}
function Test2() {
let x: typeof this.no = 1;
~~~~
!!! error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation.
}
function Test3(this: { no: number }) {
let x: typeof this.no = 1;
}
function Test4(this: { no: number } | undefined) {
let x: typeof this.no = 1;
~~~~
!!! error TS2532: Object is possibly 'undefined'.
}
class Test5 {
no = 1;
f = () => {
// should not capture this.
let x: typeof this.no = 1;
}
}
namespace Test6 {
export let f = () => {
let x: typeof this.no = 1;
~~~~
!!! error TS2331: 'this' cannot be referenced in a module or namespace body.
~~~~
!!! error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation.
}
}
module Test7 {
export let f = () => {
let x: typeof this.no = 1;
~~~~
!!! error TS2331: 'this' cannot be referenced in a module or namespace body.
~~~~
!!! error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation.
}
}
const Test8 = () => {
let x: typeof this.no = 1;
~~~~
!!! error TS7041: The containing arrow function captures the global value of 'this'.
~~
!!! error TS7017: Element implicitly has an 'any' type because type 'typeof globalThis' has no index signature.
}
class Test9 {
no = 0;
this = 0;
f() {
if (this instanceof Test9D1) {
const d1: typeof this = this;
d1.f1();
}
if (this instanceof Test9D2) {
const d2: typeof this = this;
d2.f2();
}
}
g() {
if (this.no === 1) {
const no: typeof this.no = this.no;
}
if (this.this === 1) {
const no: typeof this.this = this.this;
}
}
}
class Test9D1 {
f1() {}
}
class Test9D2 {
f2() {}
}
class Test10 {
a?: { b?: string }
foo() {
let a: typeof this.a = undefined as any;
if (this.a) {
let a: typeof this.a = undefined as any; // should narrow to { b?: string }
let b: typeof this.a.b = undefined as any;
if (this.a.b) {
let b: typeof this.a.b = undefined as any; // should narrow to string
}
}
}
}
class Test11 {
this?: { x?: string };
foo() {
const o = this;
let bar: typeof o.this = {};
if (o.this && o.this.x) {
let y: string = o.this.x; // should narrow to string
}
}
}
+243
View File
@@ -0,0 +1,243 @@
//// [typeofThis.ts]
class Test {
data = {};
constructor() {
var copy: typeof this.data = {};
}
}
class Test1 {
data = { foo: '' };
['this'] = '';
constructor() {
var copy: typeof this.data = { foo: '' };
var foo: typeof this.data.foo = '';
var self: typeof this = this;
self.data;
var str: typeof this.this = '';
}
}
function Test2() {
let x: typeof this.no = 1;
}
function Test3(this: { no: number }) {
let x: typeof this.no = 1;
}
function Test4(this: { no: number } | undefined) {
let x: typeof this.no = 1;
}
class Test5 {
no = 1;
f = () => {
// should not capture this.
let x: typeof this.no = 1;
}
}
namespace Test6 {
export let f = () => {
let x: typeof this.no = 1;
}
}
module Test7 {
export let f = () => {
let x: typeof this.no = 1;
}
}
const Test8 = () => {
let x: typeof this.no = 1;
}
class Test9 {
no = 0;
this = 0;
f() {
if (this instanceof Test9D1) {
const d1: typeof this = this;
d1.f1();
}
if (this instanceof Test9D2) {
const d2: typeof this = this;
d2.f2();
}
}
g() {
if (this.no === 1) {
const no: typeof this.no = this.no;
}
if (this.this === 1) {
const no: typeof this.this = this.this;
}
}
}
class Test9D1 {
f1() {}
}
class Test9D2 {
f2() {}
}
class Test10 {
a?: { b?: string }
foo() {
let a: typeof this.a = undefined as any;
if (this.a) {
let a: typeof this.a = undefined as any; // should narrow to { b?: string }
let b: typeof this.a.b = undefined as any;
if (this.a.b) {
let b: typeof this.a.b = undefined as any; // should narrow to string
}
}
}
}
class Test11 {
this?: { x?: string };
foo() {
const o = this;
let bar: typeof o.this = {};
if (o.this && o.this.x) {
let y: string = o.this.x; // should narrow to string
}
}
}
//// [typeofThis.js]
"use strict";
var Test = /** @class */ (function () {
function Test() {
this.data = {};
var copy = {};
}
return Test;
}());
var Test1 = /** @class */ (function () {
function Test1() {
this.data = { foo: '' };
this['this'] = '';
var copy = { foo: '' };
var foo = '';
var self = this;
self.data;
var str = '';
}
return Test1;
}());
function Test2() {
var x = 1;
}
function Test3() {
var x = 1;
}
function Test4() {
var x = 1;
}
var Test5 = /** @class */ (function () {
function Test5() {
this.no = 1;
this.f = function () {
// should not capture this.
var x = 1;
};
}
return Test5;
}());
var Test6;
(function (Test6) {
Test6.f = function () {
var x = 1;
};
})(Test6 || (Test6 = {}));
var Test7;
(function (Test7) {
Test7.f = function () {
var x = 1;
};
})(Test7 || (Test7 = {}));
var Test8 = function () {
var x = 1;
};
var Test9 = /** @class */ (function () {
function Test9() {
this.no = 0;
this["this"] = 0;
}
Test9.prototype.f = function () {
if (this instanceof Test9D1) {
var d1 = this;
d1.f1();
}
if (this instanceof Test9D2) {
var d2 = this;
d2.f2();
}
};
Test9.prototype.g = function () {
if (this.no === 1) {
var no = this.no;
}
if (this["this"] === 1) {
var no = this["this"];
}
};
return Test9;
}());
var Test9D1 = /** @class */ (function () {
function Test9D1() {
}
Test9D1.prototype.f1 = function () { };
return Test9D1;
}());
var Test9D2 = /** @class */ (function () {
function Test9D2() {
}
Test9D2.prototype.f2 = function () { };
return Test9D2;
}());
var Test10 = /** @class */ (function () {
function Test10() {
}
Test10.prototype.foo = function () {
var a = undefined;
if (this.a) {
var a_1 = undefined; // should narrow to { b?: string }
var b = undefined;
if (this.a.b) {
var b_1 = undefined; // should narrow to string
}
}
};
return Test10;
}());
var Test11 = /** @class */ (function () {
function Test11() {
}
Test11.prototype.foo = function () {
var o = this;
var bar = {};
if (o["this"] && o["this"].x) {
var y = o["this"].x; // should narrow to string
}
};
return Test11;
}());
@@ -0,0 +1,314 @@
=== tests/cases/conformance/types/specifyingTypes/typeQueries/typeofThis.ts ===
class Test {
>Test : Symbol(Test, Decl(typeofThis.ts, 0, 0))
data = {};
>data : Symbol(Test.data, Decl(typeofThis.ts, 0, 12))
constructor() {
var copy: typeof this.data = {};
>copy : Symbol(copy, Decl(typeofThis.ts, 3, 11))
>this.data : Symbol(Test.data, Decl(typeofThis.ts, 0, 12))
>data : Symbol(Test.data, Decl(typeofThis.ts, 0, 12))
}
}
class Test1 {
>Test1 : Symbol(Test1, Decl(typeofThis.ts, 5, 1))
data = { foo: '' };
>data : Symbol(Test1.data, Decl(typeofThis.ts, 7, 13))
>foo : Symbol(foo, Decl(typeofThis.ts, 8, 12))
['this'] = '';
>['this'] : Symbol(Test1['this'], Decl(typeofThis.ts, 8, 23))
>'this' : Symbol(Test1['this'], Decl(typeofThis.ts, 8, 23))
constructor() {
var copy: typeof this.data = { foo: '' };
>copy : Symbol(copy, Decl(typeofThis.ts, 11, 11))
>this.data : Symbol(Test1.data, Decl(typeofThis.ts, 7, 13))
>data : Symbol(Test1.data, Decl(typeofThis.ts, 7, 13))
>foo : Symbol(foo, Decl(typeofThis.ts, 11, 38))
var foo: typeof this.data.foo = '';
>foo : Symbol(foo, Decl(typeofThis.ts, 12, 11))
>this.data.foo : Symbol(foo, Decl(typeofThis.ts, 8, 12))
>this.data : Symbol(Test1.data, Decl(typeofThis.ts, 7, 13))
>data : Symbol(Test1.data, Decl(typeofThis.ts, 7, 13))
>foo : Symbol(foo, Decl(typeofThis.ts, 8, 12))
var self: typeof this = this;
>self : Symbol(self, Decl(typeofThis.ts, 14, 11))
>this : Symbol(Test1, Decl(typeofThis.ts, 5, 1))
self.data;
>self.data : Symbol(Test1.data, Decl(typeofThis.ts, 7, 13))
>self : Symbol(self, Decl(typeofThis.ts, 14, 11))
>data : Symbol(Test1.data, Decl(typeofThis.ts, 7, 13))
var str: typeof this.this = '';
>str : Symbol(str, Decl(typeofThis.ts, 17, 11))
>this.this : Symbol(Test1['this'], Decl(typeofThis.ts, 8, 23))
>this : Symbol(Test1['this'], Decl(typeofThis.ts, 8, 23))
}
}
function Test2() {
>Test2 : Symbol(Test2, Decl(typeofThis.ts, 19, 1))
let x: typeof this.no = 1;
>x : Symbol(x, Decl(typeofThis.ts, 23, 7))
}
function Test3(this: { no: number }) {
>Test3 : Symbol(Test3, Decl(typeofThis.ts, 24, 1))
>this : Symbol(this, Decl(typeofThis.ts, 26, 15))
>no : Symbol(no, Decl(typeofThis.ts, 26, 22))
let x: typeof this.no = 1;
>x : Symbol(x, Decl(typeofThis.ts, 27, 7))
>this.no : Symbol(no, Decl(typeofThis.ts, 26, 22))
>this : Symbol(this, Decl(typeofThis.ts, 26, 15))
>no : Symbol(no, Decl(typeofThis.ts, 26, 22))
}
function Test4(this: { no: number } | undefined) {
>Test4 : Symbol(Test4, Decl(typeofThis.ts, 28, 1))
>this : Symbol(this, Decl(typeofThis.ts, 30, 15))
>no : Symbol(no, Decl(typeofThis.ts, 30, 22))
let x: typeof this.no = 1;
>x : Symbol(x, Decl(typeofThis.ts, 31, 7))
>this.no : Symbol(no, Decl(typeofThis.ts, 30, 22))
>this : Symbol(this, Decl(typeofThis.ts, 30, 15))
>no : Symbol(no, Decl(typeofThis.ts, 30, 22))
}
class Test5 {
>Test5 : Symbol(Test5, Decl(typeofThis.ts, 32, 1))
no = 1;
>no : Symbol(Test5.no, Decl(typeofThis.ts, 34, 13))
f = () => {
>f : Symbol(Test5.f, Decl(typeofThis.ts, 35, 11))
// should not capture this.
let x: typeof this.no = 1;
>x : Symbol(x, Decl(typeofThis.ts, 39, 11))
>this.no : Symbol(Test5.no, Decl(typeofThis.ts, 34, 13))
>no : Symbol(Test5.no, Decl(typeofThis.ts, 34, 13))
}
}
namespace Test6 {
>Test6 : Symbol(Test6, Decl(typeofThis.ts, 41, 1))
export let f = () => {
>f : Symbol(f, Decl(typeofThis.ts, 44, 14))
let x: typeof this.no = 1;
>x : Symbol(x, Decl(typeofThis.ts, 45, 11))
}
}
module Test7 {
>Test7 : Symbol(Test7, Decl(typeofThis.ts, 47, 1))
export let f = () => {
>f : Symbol(f, Decl(typeofThis.ts, 50, 14))
let x: typeof this.no = 1;
>x : Symbol(x, Decl(typeofThis.ts, 51, 11))
}
}
const Test8 = () => {
>Test8 : Symbol(Test8, Decl(typeofThis.ts, 55, 5))
let x: typeof this.no = 1;
>x : Symbol(x, Decl(typeofThis.ts, 56, 7))
}
class Test9 {
>Test9 : Symbol(Test9, Decl(typeofThis.ts, 57, 1))
no = 0;
>no : Symbol(Test9.no, Decl(typeofThis.ts, 59, 13))
this = 0;
>this : Symbol(Test9.this, Decl(typeofThis.ts, 60, 11))
f() {
>f : Symbol(Test9.f, Decl(typeofThis.ts, 61, 13))
if (this instanceof Test9D1) {
>this : Symbol(Test9, Decl(typeofThis.ts, 57, 1))
>Test9D1 : Symbol(Test9D1, Decl(typeofThis.ts, 84, 1))
const d1: typeof this = this;
>d1 : Symbol(d1, Decl(typeofThis.ts, 65, 17))
d1.f1();
>d1.f1 : Symbol(Test9D1.f1, Decl(typeofThis.ts, 86, 15))
>d1 : Symbol(d1, Decl(typeofThis.ts, 65, 17))
>f1 : Symbol(Test9D1.f1, Decl(typeofThis.ts, 86, 15))
}
if (this instanceof Test9D2) {
>this : Symbol(Test9, Decl(typeofThis.ts, 57, 1))
>Test9D2 : Symbol(Test9D2, Decl(typeofThis.ts, 88, 1))
const d2: typeof this = this;
>d2 : Symbol(d2, Decl(typeofThis.ts, 70, 17))
d2.f2();
>d2.f2 : Symbol(Test9D2.f2, Decl(typeofThis.ts, 90, 15))
>d2 : Symbol(d2, Decl(typeofThis.ts, 70, 17))
>f2 : Symbol(Test9D2.f2, Decl(typeofThis.ts, 90, 15))
}
}
g() {
>g : Symbol(Test9.g, Decl(typeofThis.ts, 73, 5))
if (this.no === 1) {
>this.no : Symbol(Test9.no, Decl(typeofThis.ts, 59, 13))
>this : Symbol(Test9, Decl(typeofThis.ts, 57, 1))
>no : Symbol(Test9.no, Decl(typeofThis.ts, 59, 13))
const no: typeof this.no = this.no;
>no : Symbol(no, Decl(typeofThis.ts, 77, 17))
>this.no : Symbol(Test9.no, Decl(typeofThis.ts, 59, 13))
>no : Symbol(Test9.no, Decl(typeofThis.ts, 59, 13))
>this.no : Symbol(Test9.no, Decl(typeofThis.ts, 59, 13))
>this : Symbol(Test9, Decl(typeofThis.ts, 57, 1))
>no : Symbol(Test9.no, Decl(typeofThis.ts, 59, 13))
}
if (this.this === 1) {
>this.this : Symbol(Test9.this, Decl(typeofThis.ts, 60, 11))
>this : Symbol(Test9, Decl(typeofThis.ts, 57, 1))
>this : Symbol(Test9.this, Decl(typeofThis.ts, 60, 11))
const no: typeof this.this = this.this;
>no : Symbol(no, Decl(typeofThis.ts, 81, 17))
>this.this : Symbol(Test9.this, Decl(typeofThis.ts, 60, 11))
>this : Symbol(Test9.this, Decl(typeofThis.ts, 60, 11))
>this.this : Symbol(Test9.this, Decl(typeofThis.ts, 60, 11))
>this : Symbol(Test9, Decl(typeofThis.ts, 57, 1))
>this : Symbol(Test9.this, Decl(typeofThis.ts, 60, 11))
}
}
}
class Test9D1 {
>Test9D1 : Symbol(Test9D1, Decl(typeofThis.ts, 84, 1))
f1() {}
>f1 : Symbol(Test9D1.f1, Decl(typeofThis.ts, 86, 15))
}
class Test9D2 {
>Test9D2 : Symbol(Test9D2, Decl(typeofThis.ts, 88, 1))
f2() {}
>f2 : Symbol(Test9D2.f2, Decl(typeofThis.ts, 90, 15))
}
class Test10 {
>Test10 : Symbol(Test10, Decl(typeofThis.ts, 92, 1))
a?: { b?: string }
>a : Symbol(Test10.a, Decl(typeofThis.ts, 94, 14))
>b : Symbol(b, Decl(typeofThis.ts, 95, 9))
foo() {
>foo : Symbol(Test10.foo, Decl(typeofThis.ts, 95, 22))
let a: typeof this.a = undefined as any;
>a : Symbol(a, Decl(typeofThis.ts, 98, 11))
>this.a : Symbol(Test10.a, Decl(typeofThis.ts, 94, 14))
>a : Symbol(Test10.a, Decl(typeofThis.ts, 94, 14))
>undefined : Symbol(undefined)
if (this.a) {
>this.a : Symbol(Test10.a, Decl(typeofThis.ts, 94, 14))
>this : Symbol(Test10, Decl(typeofThis.ts, 92, 1))
>a : Symbol(Test10.a, Decl(typeofThis.ts, 94, 14))
let a: typeof this.a = undefined as any; // should narrow to { b?: string }
>a : Symbol(a, Decl(typeofThis.ts, 100, 15))
>this.a : Symbol(Test10.a, Decl(typeofThis.ts, 94, 14))
>a : Symbol(Test10.a, Decl(typeofThis.ts, 94, 14))
>undefined : Symbol(undefined)
let b: typeof this.a.b = undefined as any;
>b : Symbol(b, Decl(typeofThis.ts, 101, 15))
>this.a.b : Symbol(b, Decl(typeofThis.ts, 95, 9))
>this.a : Symbol(Test10.a, Decl(typeofThis.ts, 94, 14))
>a : Symbol(Test10.a, Decl(typeofThis.ts, 94, 14))
>b : Symbol(b, Decl(typeofThis.ts, 95, 9))
>undefined : Symbol(undefined)
if (this.a.b) {
>this.a.b : Symbol(b, Decl(typeofThis.ts, 95, 9))
>this.a : Symbol(Test10.a, Decl(typeofThis.ts, 94, 14))
>this : Symbol(Test10, Decl(typeofThis.ts, 92, 1))
>a : Symbol(Test10.a, Decl(typeofThis.ts, 94, 14))
>b : Symbol(b, Decl(typeofThis.ts, 95, 9))
let b: typeof this.a.b = undefined as any; // should narrow to string
>b : Symbol(b, Decl(typeofThis.ts, 104, 19))
>this.a.b : Symbol(b, Decl(typeofThis.ts, 95, 9))
>this.a : Symbol(Test10.a, Decl(typeofThis.ts, 94, 14))
>a : Symbol(Test10.a, Decl(typeofThis.ts, 94, 14))
>b : Symbol(b, Decl(typeofThis.ts, 95, 9))
>undefined : Symbol(undefined)
}
}
}
}
class Test11 {
>Test11 : Symbol(Test11, Decl(typeofThis.ts, 108, 1))
this?: { x?: string };
>this : Symbol(Test11.this, Decl(typeofThis.ts, 110, 14))
>x : Symbol(x, Decl(typeofThis.ts, 111, 12))
foo() {
>foo : Symbol(Test11.foo, Decl(typeofThis.ts, 111, 26))
const o = this;
>o : Symbol(o, Decl(typeofThis.ts, 114, 13))
>this : Symbol(Test11, Decl(typeofThis.ts, 108, 1))
let bar: typeof o.this = {};
>bar : Symbol(bar, Decl(typeofThis.ts, 115, 11))
>o.this : Symbol(Test11.this, Decl(typeofThis.ts, 110, 14))
>o : Symbol(o, Decl(typeofThis.ts, 114, 13))
>this : Symbol(Test11.this, Decl(typeofThis.ts, 110, 14))
if (o.this && o.this.x) {
>o.this : Symbol(Test11.this, Decl(typeofThis.ts, 110, 14))
>o : Symbol(o, Decl(typeofThis.ts, 114, 13))
>this : Symbol(Test11.this, Decl(typeofThis.ts, 110, 14))
>o.this.x : Symbol(x, Decl(typeofThis.ts, 111, 12))
>o.this : Symbol(Test11.this, Decl(typeofThis.ts, 110, 14))
>o : Symbol(o, Decl(typeofThis.ts, 114, 13))
>this : Symbol(Test11.this, Decl(typeofThis.ts, 110, 14))
>x : Symbol(x, Decl(typeofThis.ts, 111, 12))
let y: string = o.this.x; // should narrow to string
>y : Symbol(y, Decl(typeofThis.ts, 118, 15))
>o.this.x : Symbol(x, Decl(typeofThis.ts, 111, 12))
>o.this : Symbol(Test11.this, Decl(typeofThis.ts, 110, 14))
>o : Symbol(o, Decl(typeofThis.ts, 114, 13))
>this : Symbol(Test11.this, Decl(typeofThis.ts, 110, 14))
>x : Symbol(x, Decl(typeofThis.ts, 111, 12))
}
}
}
+379
View File
@@ -0,0 +1,379 @@
=== tests/cases/conformance/types/specifyingTypes/typeQueries/typeofThis.ts ===
class Test {
>Test : Test
data = {};
>data : {}
>{} : {}
constructor() {
var copy: typeof this.data = {};
>copy : {}
>this.data : {}
>this : any
>data : {}
>{} : {}
}
}
class Test1 {
>Test1 : Test1
data = { foo: '' };
>data : { foo: string; }
>{ foo: '' } : { foo: string; }
>foo : string
>'' : ""
['this'] = '';
>['this'] : string
>'this' : "this"
>'' : ""
constructor() {
var copy: typeof this.data = { foo: '' };
>copy : { foo: string; }
>this.data : { foo: string; }
>this : any
>data : { foo: string; }
>{ foo: '' } : { foo: string; }
>foo : string
>'' : ""
var foo: typeof this.data.foo = '';
>foo : string
>this.data.foo : string
>this.data : { foo: string; }
>this : any
>data : { foo: string; }
>foo : string
>'' : ""
var self: typeof this = this;
>self : this
>this : any
>this : this
self.data;
>self.data : { foo: string; }
>self : this
>data : { foo: string; }
var str: typeof this.this = '';
>str : string
>this.this : string
>this : any
>this : string
>'' : ""
}
}
function Test2() {
>Test2 : () => void
let x: typeof this.no = 1;
>x : any
>this.no : any
>this : any
>no : any
>1 : 1
}
function Test3(this: { no: number }) {
>Test3 : (this: { no: number;}) => void
>this : { no: number; }
>no : number
let x: typeof this.no = 1;
>x : number
>this.no : number
>this : { no: number; }
>no : number
>1 : 1
}
function Test4(this: { no: number } | undefined) {
>Test4 : (this: { no: number;} | undefined) => void
>this : { no: number; } | undefined
>no : number
let x: typeof this.no = 1;
>x : number
>this.no : number
>this : { no: number; } | undefined
>no : number
>1 : 1
}
class Test5 {
>Test5 : Test5
no = 1;
>no : number
>1 : 1
f = () => {
>f : () => void
>() => { // should not capture this. let x: typeof this.no = 1; } : () => void
// should not capture this.
let x: typeof this.no = 1;
>x : number
>this.no : number
>this : any
>no : number
>1 : 1
}
}
namespace Test6 {
>Test6 : typeof Test6
export let f = () => {
>f : () => void
>() => { let x: typeof this.no = 1; } : () => void
let x: typeof this.no = 1;
>x : any
>this.no : any
>this : any
>no : any
>1 : 1
}
}
module Test7 {
>Test7 : typeof Test7
export let f = () => {
>f : () => void
>() => { let x: typeof this.no = 1; } : () => void
let x: typeof this.no = 1;
>x : any
>this.no : any
>this : any
>no : any
>1 : 1
}
}
const Test8 = () => {
>Test8 : () => void
>() => { let x: typeof this.no = 1;} : () => void
let x: typeof this.no = 1;
>x : any
>this.no : any
>this : any
>no : any
>1 : 1
}
class Test9 {
>Test9 : Test9
no = 0;
>no : number
>0 : 0
this = 0;
>this : number
>0 : 0
f() {
>f : () => void
if (this instanceof Test9D1) {
>this instanceof Test9D1 : boolean
>this : this
>Test9D1 : typeof Test9D1
const d1: typeof this = this;
>d1 : this & Test9D1
>this : any
>this : this & Test9D1
d1.f1();
>d1.f1() : void
>d1.f1 : () => void
>d1 : this & Test9D1
>f1 : () => void
}
if (this instanceof Test9D2) {
>this instanceof Test9D2 : boolean
>this : this
>Test9D2 : typeof Test9D2
const d2: typeof this = this;
>d2 : this & Test9D2
>this : any
>this : this & Test9D2
d2.f2();
>d2.f2() : void
>d2.f2 : () => void
>d2 : this & Test9D2
>f2 : () => void
}
}
g() {
>g : () => void
if (this.no === 1) {
>this.no === 1 : boolean
>this.no : number
>this : this
>no : number
>1 : 1
const no: typeof this.no = this.no;
>no : 1
>this.no : 1
>this : any
>no : 1
>this.no : 1
>this : this
>no : 1
}
if (this.this === 1) {
>this.this === 1 : boolean
>this.this : number
>this : this
>this : number
>1 : 1
const no: typeof this.this = this.this;
>no : 1
>this.this : 1
>this : any
>this : 1
>this.this : 1
>this : this
>this : 1
}
}
}
class Test9D1 {
>Test9D1 : Test9D1
f1() {}
>f1 : () => void
}
class Test9D2 {
>Test9D2 : Test9D2
f2() {}
>f2 : () => void
}
class Test10 {
>Test10 : Test10
a?: { b?: string }
>a : { b?: string; } | undefined
>b : string | undefined
foo() {
>foo : () => void
let a: typeof this.a = undefined as any;
>a : { b?: string; } | undefined
>this.a : { b?: string; } | undefined
>this : any
>a : { b?: string; } | undefined
>undefined as any : any
>undefined : undefined
if (this.a) {
>this.a : { b?: string; } | undefined
>this : this
>a : { b?: string; } | undefined
let a: typeof this.a = undefined as any; // should narrow to { b?: string }
>a : { b?: string; }
>this.a : { b?: string; }
>this : any
>a : { b?: string; }
>undefined as any : any
>undefined : undefined
let b: typeof this.a.b = undefined as any;
>b : string | undefined
>this.a.b : string | undefined
>this.a : { b?: string; }
>this : any
>a : { b?: string; }
>b : string | undefined
>undefined as any : any
>undefined : undefined
if (this.a.b) {
>this.a.b : string | undefined
>this.a : { b?: string; }
>this : this
>a : { b?: string; }
>b : string | undefined
let b: typeof this.a.b = undefined as any; // should narrow to string
>b : string
>this.a.b : string
>this.a : { b?: string; }
>this : any
>a : { b?: string; }
>b : string
>undefined as any : any
>undefined : undefined
}
}
}
}
class Test11 {
>Test11 : Test11
this?: { x?: string };
>this : { x?: string; } | undefined
>x : string | undefined
foo() {
>foo : () => void
const o = this;
>o : this
>this : this
let bar: typeof o.this = {};
>bar : { x?: string; } | undefined
>o.this : { x?: string; } | undefined
>o : this
>this : { x?: string; } | undefined
>{} : {}
if (o.this && o.this.x) {
>o.this && o.this.x : string | undefined
>o.this : { x?: string; } | undefined
>o : this
>this : { x?: string; } | undefined
>o.this.x : string | undefined
>o.this : { x?: string; }
>o : this
>this : { x?: string; }
>x : string | undefined
let y: string = o.this.x; // should narrow to string
>y : string
>o.this.x : string
>o.this : { x?: string; }
>o : this
>this : { x?: string; }
>x : string
}
}
}
@@ -0,0 +1,10 @@
//// [typeofThisWithImplicitThis.ts]
function Test1() {
let x: typeof this.no = 1
}
//// [typeofThisWithImplicitThis.js]
function Test1() {
var x = 1;
}
@@ -0,0 +1,8 @@
=== tests/cases/conformance/types/specifyingTypes/typeQueries/typeofThisWithImplicitThis.ts ===
function Test1() {
>Test1 : Symbol(Test1, Decl(typeofThisWithImplicitThis.ts, 0, 0))
let x: typeof this.no = 1
>x : Symbol(x, Decl(typeofThisWithImplicitThis.ts, 1, 7))
}
@@ -0,0 +1,12 @@
=== tests/cases/conformance/types/specifyingTypes/typeQueries/typeofThisWithImplicitThis.ts ===
function Test1() {
>Test1 : () => void
let x: typeof this.no = 1
>x : any
>this.no : any
>this : any
>no : any
>1 : 1
}
@@ -14,7 +14,7 @@ class D {
class E {
a = this.x; // ok
b: typeof this.x; // error
b: typeof this.x; // ok
constructor(public x) { }
}
@@ -0,0 +1,125 @@
// @noImplicitThis: true
// @strict: true
class Test {
data = {};
constructor() {
var copy: typeof this.data = {};
}
}
class Test1 {
data = { foo: '' };
['this'] = '';
constructor() {
var copy: typeof this.data = { foo: '' };
var foo: typeof this.data.foo = '';
var self: typeof this = this;
self.data;
var str: typeof this.this = '';
}
}
function Test2() {
let x: typeof this.no = 1;
}
function Test3(this: { no: number }) {
let x: typeof this.no = 1;
}
function Test4(this: { no: number } | undefined) {
let x: typeof this.no = 1;
}
class Test5 {
no = 1;
f = () => {
// should not capture this.
let x: typeof this.no = 1;
}
}
namespace Test6 {
export let f = () => {
let x: typeof this.no = 1;
}
}
module Test7 {
export let f = () => {
let x: typeof this.no = 1;
}
}
const Test8 = () => {
let x: typeof this.no = 1;
}
class Test9 {
no = 0;
this = 0;
f() {
if (this instanceof Test9D1) {
const d1: typeof this = this;
d1.f1();
}
if (this instanceof Test9D2) {
const d2: typeof this = this;
d2.f2();
}
}
g() {
if (this.no === 1) {
const no: typeof this.no = this.no;
}
if (this.this === 1) {
const no: typeof this.this = this.this;
}
}
}
class Test9D1 {
f1() {}
}
class Test9D2 {
f2() {}
}
class Test10 {
a?: { b?: string }
foo() {
let a: typeof this.a = undefined as any;
if (this.a) {
let a: typeof this.a = undefined as any; // should narrow to { b?: string }
let b: typeof this.a.b = undefined as any;
if (this.a.b) {
let b: typeof this.a.b = undefined as any; // should narrow to string
}
}
}
}
class Test11 {
this?: { x?: string };
foo() {
const o = this;
let bar: typeof o.this = {};
if (o.this && o.this.x) {
let y: string = o.this.x; // should narrow to string
}
}
}
@@ -0,0 +1,5 @@
// @noImplicitThis: false
function Test1() {
let x: typeof this.no = 1
}