Merge pull request #5474 from Microsoft/forbid-this-as-constructor-parameter-type
Forbid this as constructor parameter type
This commit is contained in:
commit
cc64210519
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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 {
|
||||
|
|
23
tests/baselines/reference/thisTypeErrors2.errors.txt
Normal file
23
tests/baselines/reference/thisTypeErrors2.errors.txt
Normal file
|
@ -0,0 +1,23 @@
|
|||
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.
|
||||
let self: this = this;
|
||||
this.n = 12;
|
||||
}
|
||||
}
|
||||
|
35
tests/baselines/reference/thisTypeErrors2.js
Normal file
35
tests/baselines/reference/thisTypeErrors2.js
Normal file
|
@ -0,0 +1,35 @@
|
|||
//// [thisTypeErrors2.ts]
|
||||
class Base {
|
||||
constructor(a: this) {
|
||||
}
|
||||
}
|
||||
class Generic<T> {
|
||||
}
|
||||
class Derived {
|
||||
n: number;
|
||||
constructor(public host: Generic<this>) {
|
||||
let self: this = 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;
|
||||
var self = this;
|
||||
this.n = 12;
|
||||
}
|
||||
return Derived;
|
||||
})();
|
57
tests/baselines/reference/thisTypeInClasses.errors.txt
Normal file
57
tests/baselines/reference/thisTypeInClasses.errors.txt
Normal file
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
13
tests/cases/conformance/types/thisType/thisTypeErrors2.ts
Normal file
13
tests/cases/conformance/types/thisType/thisTypeErrors2.ts
Normal file
|
@ -0,0 +1,13 @@
|
|||
class Base {
|
||||
constructor(a: this) {
|
||||
}
|
||||
}
|
||||
class Generic<T> {
|
||||
}
|
||||
class Derived {
|
||||
n: number;
|
||||
constructor(public host: Generic<this>) {
|
||||
let self: this = this;
|
||||
this.n = 12;
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue