Merge pull request #5474 from Microsoft/forbid-this-as-constructor-parameter-type

Forbid this as constructor parameter type
This commit is contained in:
Nathan Shively-Sanders 2015-11-02 11:04:36 -08:00
commit cc64210519
8 changed files with 142 additions and 10 deletions

View file

@ -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;
}
}

View file

@ -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)) {

View file

@ -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)) {

View file

@ -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 {

View 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;
}
}

View 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;
})();

View 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;
}
}

View 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;
}
}