Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

allow this in typeQuery #43898

Merged
merged 7 commits into from
Jun 17, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13102,7 +13102,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) ? getThisType(node.exprName) : checkExpression(node.exprName);
links.resolvedType = getRegularTypeOfLiteralType(getWidenedType(type));
}
return links.resolvedType;
}
Expand Down Expand Up @@ -27077,7 +27078,8 @@ namespace ts {
}

function checkQualifiedName(node: QualifiedName, checkMode: CheckMode | undefined) {
return checkPropertyAccessExpressionOrQualifiedName(node, node.left, checkNonNullExpression(node.left), node.right, checkMode);
const leftType = isTypeQueryNode(node.parent) && isThisIdentifier(node.left) ? checkNonNullType(getThisType(node.left), node.left) : checkNonNullExpression(node.left);
return checkPropertyAccessExpressionOrQualifiedName(node, node.left, leftType, node.right, checkMode);
}

function isMethodAccessForCall(node: Node) {
Expand Down
Original file line number Diff line number Diff line change
@@ -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'.


Expand All @@ -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;
~
Expand All @@ -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;
~
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -32,8 +31,6 @@ tests/cases/conformance/classes/propertyMemberDeclarations/initializerReferencin
class E {
a = this.x; // ok
b: typeof this.x; // error
Zzzen marked this conversation as resolved.
Show resolved Hide resolved
~~~~
!!! error TS2304: Cannot find name 'this'.
constructor(public x) { }
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ class E {

b: typeof this.x; // error
>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))
Expand Down
41 changes: 41 additions & 0 deletions tests/baselines/reference/typeofThis.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
//// [typeofThis.ts]
class Test {
data = {};
constructor() {
var copy: typeof this.data = {};
}
}

class Test1 {
data = { foo: '' };
['this'] = '';
constructor() {
var copy: typeof this.data = { foo: '' };

var self: typeof this = this;
self.data;

var str: typeof this.this = '';
}
}


//// [typeofThis.js]
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 self = this;
self.data;
var str = '';
}
return Test1;
}());
49 changes: 49 additions & 0 deletions tests/baselines/reference/typeofThis.symbols
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
=== 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 self: typeof this = this;
>self : Symbol(self, Decl(typeofThis.ts, 13, 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, 13, 11))
>data : Symbol(Test1.data, Decl(typeofThis.ts, 7, 13))

var str: typeof this.this = '';
>str : Symbol(str, Decl(typeofThis.ts, 16, 11))
>this.this : Symbol(Test1['this'], Decl(typeofThis.ts, 8, 23))
>this : Symbol(Test1['this'], Decl(typeofThis.ts, 8, 23))
}
}

61 changes: 61 additions & 0 deletions tests/baselines/reference/typeofThis.types
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
=== 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 self: typeof this = this;
>self : this
>this : error
>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
>'' : ""
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
class Test {
data = {};
constructor() {
var copy: typeof this.data = {};
}
}

class Test1 {
data = { foo: '' };
['this'] = '';
constructor() {
var copy: typeof this.data = { foo: '' };

var self: typeof this = this;
self.data;

var str: typeof this.this = '';
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please add tests of

  1. implicitly any usage, like function f() { let x: typeof this.no = 1 }. (x should have type any)
  2. implicit any errors for the same code, but when noImplicitThis: true
  3. The same usage in function f (this: { no: number })
  4. usage inside arrow functions, to make sure that the emit is correct. It would be good to have an arrow function inside a container that binds this, like a class, and in one that doesn't, like a module.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ooops, this type can not be used in plain functions. 🤷

    function Test1() {
        let x: typeof this.no = 1
                      ~~~~
!!! error TS2526: A 'this' type is available only in a non-static member of a class or interface.
    }
    

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That error is wrong, then, because this.no is an expression, not a type. The type would be like let x: this['no'].

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did not notice the differences between this type and this expression. Changing getThisType to checkThisExpression fixed it.