Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
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
3 changes: 2 additions & 1 deletion src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4420,7 +4420,8 @@ namespace ts {
let container = getThisContainer(node, /*includeArrowFunctions*/ false);
let parent = container && container.parent;
if (parent && (isClassLike(parent) || parent.kind === SyntaxKind.InterfaceDeclaration)) {
if (!(container.flags & NodeFlags.Static)) {
if (!(container.flags & NodeFlags.Static) &&
(container.kind !== SyntaxKind.Constructor || isNodeDescendentOf(node, (<ConstructorDeclaration>container).body))) {
return getDeclaredTypeOfClassOrInterface(getSymbolOfNode(parent)).thisType;
}
}
Expand Down
8 changes: 0 additions & 8 deletions src/compiler/emitter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -359,14 +359,6 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
sourceMaps: sourceMapDataList
};

function isNodeDescendentOf(node: Node, ancestor: Node): boolean {
while (node) {
if (node === ancestor) return true;
node = node.parent;
}
return false;
}

function isUniqueLocalName(name: string, container: Node): boolean {
for (let node = container; isNodeDescendentOf(node, container); node = node.nextContainer) {
if (node.locals && hasProperty(node.locals, name)) {
Expand Down
8 changes: 8 additions & 0 deletions src/compiler/utilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1167,6 +1167,14 @@ namespace ts {
return !!node && (node.kind === SyntaxKind.ArrayBindingPattern || node.kind === SyntaxKind.ObjectBindingPattern);
}

export function isNodeDescendentOf(node: Node, ancestor: Node): boolean {
while (node) {
if (node === ancestor) return true;
node = node.parent;
}
return false;
}

export function isInAmbientContext(node: Node): boolean {
while (node) {
if (node.flags & (NodeFlags.Ambient | NodeFlags.DeclarationFile)) {
Expand Down
5 changes: 4 additions & 1 deletion tests/baselines/reference/declarationFiles.errors.txt
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
tests/cases/conformance/types/thisType/declarationFiles.ts(5,20): error TS2526: A 'this' type is available only in a non-static member of a class or interface.
tests/cases/conformance/types/thisType/declarationFiles.ts(31,5): error TS2527: The inferred type of 'x1' references an inaccessible 'this' type. A type annotation is necessary.
tests/cases/conformance/types/thisType/declarationFiles.ts(33,5): error TS2527: The inferred type of 'x3' references an inaccessible 'this' type. A type annotation is necessary.
tests/cases/conformance/types/thisType/declarationFiles.ts(35,5): error TS2527: The inferred type of 'f1' references an inaccessible 'this' type. A type annotation is necessary.
tests/cases/conformance/types/thisType/declarationFiles.ts(41,5): error TS2527: The inferred type of 'f3' references an inaccessible 'this' type. A type annotation is necessary.


==== tests/cases/conformance/types/thisType/declarationFiles.ts (4 errors) ====
==== tests/cases/conformance/types/thisType/declarationFiles.ts (5 errors) ====

class C1 {
x: this;
f(x: this): this { return undefined; }
constructor(x: this) { }
~~~~
!!! error TS2526: A 'this' type is available only in a non-static member of a class or interface.
}

class C2 {
Expand Down
22 changes: 22 additions & 0 deletions tests/baselines/reference/thisTypeErrors2.errors.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
tests/cases/conformance/types/thisType/thisTypeErrors2.ts(2,20): error TS2526: A 'this' type is available only in a non-static member of a class or interface.
tests/cases/conformance/types/thisType/thisTypeErrors2.ts(9,38): error TS2526: A 'this' type is available only in a non-static member of a class or interface.


==== tests/cases/conformance/types/thisType/thisTypeErrors2.ts (2 errors) ====
class Base {
constructor(a: this) {
~~~~
!!! error TS2526: A 'this' type is available only in a non-static member of a class or interface.
}
}
class Generic<T> {
}
class Derived {
n: number;
constructor(public host: Generic<this>) {
~~~~
!!! error TS2526: A 'this' type is available only in a non-static member of a class or interface.
this.n = 12;
}
}

33 changes: 33 additions & 0 deletions tests/baselines/reference/thisTypeErrors2.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
//// [thisTypeErrors2.ts]
class Base {
constructor(a: this) {
}
}
class Generic<T> {
}
class Derived {
n: number;
constructor(public host: Generic<this>) {
this.n = 12;
}
}


//// [thisTypeErrors2.js]
var Base = (function () {
function Base(a) {
}
return Base;
})();
var Generic = (function () {
function Generic() {
}
return Generic;
})();
var Derived = (function () {
function Derived(host) {
this.host = host;
this.n = 12;
}
return Derived;
})();
57 changes: 57 additions & 0 deletions tests/baselines/reference/thisTypeInClasses.errors.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
tests/cases/conformance/types/thisType/thisTypeInClasses.ts(4,20): error TS2526: A 'this' type is available only in a non-static member of a class or interface.


==== tests/cases/conformance/types/thisType/thisTypeInClasses.ts (1 errors) ====
class C1 {
x: this;
f(x: this): this { return undefined; }
constructor(x: this) { }
~~~~
!!! error TS2526: A 'this' type is available only in a non-static member of a class or interface.
}

class C2 {
[x: string]: this;
}

interface Foo<T> {
x: T;
y: this;
}

class C3 {
a: this[];
b: [this, this];
c: this | Date;
d: this & Date;
e: (((this)));
f: (x: this) => this;
g: new (x: this) => this;
h: Foo<this>;
i: Foo<this | (() => this)>;
j: (x: any) => x is this;
}

declare class C4 {
x: this;
f(x: this): this;
}

class C5 {
foo() {
let f1 = (x: this): this => this;
let f2 = (x: this) => this;
let f3 = (x: this) => (y: this) => this;
let f4 = (x: this) => {
let g = (y: this) => {
return () => this;
}
return g(this);
}
}
bar() {
let x1 = <this>undefined;
let x2 = undefined as this;
}
}

12 changes: 12 additions & 0 deletions tests/cases/conformance/types/thisType/thisTypeErrors2.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
class Base {
constructor(a: this) {
}
}
class Generic<T> {
}
class Derived {
n: number;
constructor(public host: Generic<this>) {
Copy link
Member

Choose a reason for hiding this comment

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

Maybe use this in a type annotation of a local variable to test that this can be referenced in the body of a constructor.

this.n = 12;
}
}