Type 'this' in object literal function properties

Previously, methods of object literals would give a type to 'this'.
Now function properties of object literals also give a type to 'this'.
This commit is contained in:
Nathan Shively-Sanders
2016-04-29 10:31:01 -07:00
parent 91201211f4
commit c12cb83fb7
20 changed files with 158 additions and 87 deletions
+3 -2
View File
@@ -8206,10 +8206,11 @@ namespace ts {
if (signature.thisType) {
return signature.thisType;
}
if (container.parent && container.parent.kind === SyntaxKind.ObjectLiteralExpression) {
const parentObject = container.parent && container.parent.kind === SyntaxKind.PropertyAssignment ? container.parent.parent : container.parent;
if (parentObject && parentObject.kind === SyntaxKind.ObjectLiteralExpression) {
// Note: this works because object literal methods are deferred,
// which means that the type of the containing object literal is already known.
const type = checkExpressionCached(<ObjectLiteralExpression>container.parent);
const type = checkExpressionCached(<ObjectLiteralExpression>parentObject);
if (type) {
return type;
}
@@ -1,7 +1,8 @@
tests/cases/compiler/commentsOnObjectLiteral2.ts(1,14): error TS2304: Cannot find name 'makeClass'.
tests/cases/compiler/commentsOnObjectLiteral2.ts(9,17): error TS2339: Property 'name' does not exist on type '{ initialize: (name: any) => void; }'.
==== tests/cases/compiler/commentsOnObjectLiteral2.ts (1 errors) ====
==== tests/cases/compiler/commentsOnObjectLiteral2.ts (2 errors) ====
var Person = makeClass(
~~~~~~~~~
!!! error TS2304: Cannot find name 'makeClass'.
@@ -13,6 +14,8 @@ tests/cases/compiler/commentsOnObjectLiteral2.ts(1,14): error TS2304: Cannot fin
*/
initialize: function(name) {
this.name = name;
~~~~
!!! error TS2339: Property 'name' does not exist on type '{ initialize: (name: any) => void; }'.
} /* trailing comment 1*/,
}
);
@@ -163,6 +163,11 @@ var messenger = {
setTimeout(() => { this.message.toString(); }, 3000);
>setTimeout : Symbol(setTimeout, Decl(fatarrowfunctions.ts, 34, 1))
>this.message.toString : Symbol(String.toString, Decl(lib.d.ts, --, --))
>this.message : Symbol(message, Decl(fatarrowfunctions.ts, 38, 17))
>this : Symbol(, Decl(fatarrowfunctions.ts, 38, 15))
>message : Symbol(message, Decl(fatarrowfunctions.ts, 38, 17))
>toString : Symbol(String.toString, Decl(lib.d.ts, --, --))
}
};
@@ -234,12 +234,12 @@ var messenger = {
>setTimeout(() => { this.message.toString(); }, 3000) : number
>setTimeout : (expression: any, msec?: number, language?: any) => number
>() => { this.message.toString(); } : () => void
>this.message.toString() : any
>this.message.toString : any
>this.message : any
>this : any
>message : any
>toString : any
>this.message.toString() : string
>this.message.toString : () => string
>this.message : string
>this : { message: string; start: () => void; }
>message : string
>toString : () => string
>3000 : number
}
};
@@ -16,12 +16,17 @@ var messenger = {
var _self = this;
>_self : Symbol(_self, Decl(fatarrowfunctionsInFunctions.ts, 5, 11))
>this : Symbol(, Decl(fatarrowfunctionsInFunctions.ts, 2, 15))
setTimeout(function() {
>setTimeout : Symbol(setTimeout, Decl(fatarrowfunctionsInFunctions.ts, 0, 0))
_self.message.toString();
>_self.message.toString : Symbol(String.toString, Decl(lib.d.ts, --, --))
>_self.message : Symbol(message, Decl(fatarrowfunctionsInFunctions.ts, 2, 17))
>_self : Symbol(_self, Decl(fatarrowfunctionsInFunctions.ts, 5, 11))
>message : Symbol(message, Decl(fatarrowfunctionsInFunctions.ts, 2, 17))
>toString : Symbol(String.toString, Decl(lib.d.ts, --, --))
}, 3000);
}
@@ -18,8 +18,8 @@ var messenger = {
>function() { var _self = this; setTimeout(function() { _self.message.toString(); }, 3000); } : () => void
var _self = this;
>_self : any
>this : any
>_self : { message: string; start: () => void; }
>this : { message: string; start: () => void; }
setTimeout(function() {
>setTimeout(function() { _self.message.toString(); }, 3000) : number
@@ -27,12 +27,12 @@ var messenger = {
>function() { _self.message.toString(); } : () => void
_self.message.toString();
>_self.message.toString() : any
>_self.message.toString : any
>_self.message : any
>_self : any
>message : any
>toString : any
>_self.message.toString() : string
>_self.message.toString : () => string
>_self.message : string
>_self : { message: string; start: () => void; }
>message : string
>toString : () => string
}, 3000);
>3000 : number
@@ -1,12 +1,13 @@
tests/cases/conformance/types/thisType/looseThisTypeInFunctions.ts(21,1): error TS2322: Type '(this: C, m: number) => number' is not assignable to type '(this: void, m: number) => number'.
The 'this' types of each signature are incompatible.
Type 'void' is not assignable to type 'C'.
tests/cases/conformance/types/thisType/looseThisTypeInFunctions.ts(25,27): error TS2339: Property 'length' does not exist on type 'number'.
tests/cases/conformance/types/thisType/looseThisTypeInFunctions.ts(33,28): error TS2339: Property 'length' does not exist on type 'number'.
tests/cases/conformance/types/thisType/looseThisTypeInFunctions.ts(37,9): error TS2684: The 'this' context of type 'void' is not assignable to method's 'this' of type 'I'.
tests/cases/conformance/types/thisType/looseThisTypeInFunctions.ts(46,20): error TS2339: Property 'length' does not exist on type 'number'.
==== tests/cases/conformance/types/thisType/looseThisTypeInFunctions.ts (4 errors) ====
==== tests/cases/conformance/types/thisType/looseThisTypeInFunctions.ts (5 errors) ====
interface I {
n: number;
explicitThis(this: this, m: number): number;
@@ -36,6 +37,8 @@ tests/cases/conformance/types/thisType/looseThisTypeInFunctions.ts(46,20): error
n: 101,
explicitThis: function (m: number) {
return m + this.n.length; // ok, this.n: any
~~~~~~
!!! error TS2339: Property 'length' does not exist on type 'number'.
},
implicitThis(m: number): number { return m; }
};
@@ -37,8 +37,15 @@ var o = {
>onmousemove : Symbol(Window.onmousemove, Decl(selfInLambdas.ts, 6, 18))
this.counter++
>this.counter : Symbol(counter, Decl(selfInLambdas.ts, 10, 9))
>this : Symbol(, Decl(selfInLambdas.ts, 10, 7))
>counter : Symbol(counter, Decl(selfInLambdas.ts, 10, 9))
var f = () => this.counter;
>f : Symbol(f, Decl(selfInLambdas.ts, 18, 15))
>this.counter : Symbol(counter, Decl(selfInLambdas.ts, 10, 9))
>this : Symbol(, Decl(selfInLambdas.ts, 10, 7))
>counter : Symbol(counter, Decl(selfInLambdas.ts, 10, 9))
}
@@ -43,16 +43,16 @@ var o = {
this.counter++
>this.counter++ : number
>this.counter : any
>this : any
>counter : any
>this.counter : number
>this : { counter: number; start: () => void; }
>counter : number
var f = () => this.counter;
>f : () => any
>() => this.counter : () => any
>this.counter : any
>this : any
>counter : any
>f : () => number
>() => this.counter : () => number
>this.counter : number
>this : { counter: number; start: () => void; }
>counter : number
}
@@ -50,6 +50,9 @@ var messenger = {
return setTimeout(() => { var x = this.message; }, 3000);
>setTimeout : Symbol(setTimeout, Decl(thisBinding2.ts, 12, 1))
>x : Symbol(x, Decl(thisBinding2.ts, 17, 37))
>this.message : Symbol(message, Decl(thisBinding2.ts, 14, 17))
>this : Symbol(, Decl(thisBinding2.ts, 14, 15))
>message : Symbol(message, Decl(thisBinding2.ts, 14, 17))
}
};
+4 -4
View File
@@ -67,10 +67,10 @@ var messenger = {
>setTimeout(() => { var x = this.message; }, 3000) : number
>setTimeout : (expression: any, msec?: number, language?: any) => number
>() => { var x = this.message; } : () => void
>x : any
>this.message : any
>this : any
>message : any
>x : string
>this.message : string
>this : { message: string; start: () => number; }
>message : string
>3000 : number
}
};
@@ -70,6 +70,7 @@ class A {
a: function() { return this; },
>a : Symbol(a, Decl(thisInPropertyBoundDeclarations.ts, 33, 13))
>this : Symbol(, Decl(thisInPropertyBoundDeclarations.ts, 33, 11))
};
@@ -79,6 +80,7 @@ class A {
return {
a: function() { return this; },
>a : Symbol(a, Decl(thisInPropertyBoundDeclarations.ts, 38, 16))
>this : Symbol(, Decl(thisInPropertyBoundDeclarations.ts, 38, 14))
};
};
@@ -84,9 +84,9 @@ class A {
>{ a: function() { return this; }, } : { a: () => any; }
a: function() { return this; },
>a : () => any
>function() { return this; } : () => any
>this : any
>a : () => { a: any; }
>function() { return this; } : () => { a: any; }
>this : { a: () => any; }
};
@@ -98,9 +98,9 @@ class A {
>{ a: function() { return this; }, } : { a: () => any; }
a: function() { return this; },
>a : () => any
>function() { return this; } : () => any
>this : any
>a : () => { a: any; }
>function() { return this; } : () => { a: any; }
>this : { a: () => any; }
};
};
@@ -3,8 +3,12 @@ let o = {
d: "bar",
m() {
return this.d.length;
},
f: function() {
return this.d.length;
}
}
let mutuallyRecursive = {
a: 100,
start() {
@@ -35,6 +39,9 @@ var o = {
d: "bar",
m: function () {
return this.d.length;
},
f: function () {
return this.d.length;
}
};
var mutuallyRecursive = {
@@ -13,80 +13,92 @@ let o = {
>this.d : Symbol(d, Decl(thisTypeInObjectLiterals.ts, 0, 9))
>this : Symbol(, Decl(thisTypeInObjectLiterals.ts, 0, 7))
>d : Symbol(d, Decl(thisTypeInObjectLiterals.ts, 0, 9))
>length : Symbol(String.length, Decl(lib.d.ts, --, --))
},
f: function() {
>f : Symbol(f, Decl(thisTypeInObjectLiterals.ts, 4, 6))
return this.d.length;
>this.d.length : Symbol(String.length, Decl(lib.d.ts, --, --))
>this.d : Symbol(d, Decl(thisTypeInObjectLiterals.ts, 0, 9))
>this : Symbol(, Decl(thisTypeInObjectLiterals.ts, 0, 7))
>d : Symbol(d, Decl(thisTypeInObjectLiterals.ts, 0, 9))
>length : Symbol(String.length, Decl(lib.d.ts, --, --))
}
}
let mutuallyRecursive = {
>mutuallyRecursive : Symbol(mutuallyRecursive, Decl(thisTypeInObjectLiterals.ts, 6, 3))
>mutuallyRecursive : Symbol(mutuallyRecursive, Decl(thisTypeInObjectLiterals.ts, 10, 3))
a: 100,
>a : Symbol(a, Decl(thisTypeInObjectLiterals.ts, 6, 25))
>a : Symbol(a, Decl(thisTypeInObjectLiterals.ts, 10, 25))
start() {
>start : Symbol(start, Decl(thisTypeInObjectLiterals.ts, 7, 11))
>start : Symbol(start, Decl(thisTypeInObjectLiterals.ts, 11, 11))
return this.passthrough(this.a);
>this.passthrough : Symbol(passthrough, Decl(thisTypeInObjectLiterals.ts, 10, 6))
>this : Symbol(, Decl(thisTypeInObjectLiterals.ts, 6, 23))
>passthrough : Symbol(passthrough, Decl(thisTypeInObjectLiterals.ts, 10, 6))
>this.a : Symbol(a, Decl(thisTypeInObjectLiterals.ts, 6, 25))
>this : Symbol(, Decl(thisTypeInObjectLiterals.ts, 6, 23))
>a : Symbol(a, Decl(thisTypeInObjectLiterals.ts, 6, 25))
>this.passthrough : Symbol(passthrough, Decl(thisTypeInObjectLiterals.ts, 14, 6))
>this : Symbol(, Decl(thisTypeInObjectLiterals.ts, 10, 23))
>passthrough : Symbol(passthrough, Decl(thisTypeInObjectLiterals.ts, 14, 6))
>this.a : Symbol(a, Decl(thisTypeInObjectLiterals.ts, 10, 25))
>this : Symbol(, Decl(thisTypeInObjectLiterals.ts, 10, 23))
>a : Symbol(a, Decl(thisTypeInObjectLiterals.ts, 10, 25))
},
passthrough(n: number) {
>passthrough : Symbol(passthrough, Decl(thisTypeInObjectLiterals.ts, 10, 6))
>n : Symbol(n, Decl(thisTypeInObjectLiterals.ts, 11, 16))
>passthrough : Symbol(passthrough, Decl(thisTypeInObjectLiterals.ts, 14, 6))
>n : Symbol(n, Decl(thisTypeInObjectLiterals.ts, 15, 16))
return this.sub1(n);
>this.sub1 : Symbol(sub1, Decl(thisTypeInObjectLiterals.ts, 13, 6))
>this : Symbol(, Decl(thisTypeInObjectLiterals.ts, 6, 23))
>sub1 : Symbol(sub1, Decl(thisTypeInObjectLiterals.ts, 13, 6))
>n : Symbol(n, Decl(thisTypeInObjectLiterals.ts, 11, 16))
>this.sub1 : Symbol(sub1, Decl(thisTypeInObjectLiterals.ts, 17, 6))
>this : Symbol(, Decl(thisTypeInObjectLiterals.ts, 10, 23))
>sub1 : Symbol(sub1, Decl(thisTypeInObjectLiterals.ts, 17, 6))
>n : Symbol(n, Decl(thisTypeInObjectLiterals.ts, 15, 16))
},
sub1(n: number): number {
>sub1 : Symbol(sub1, Decl(thisTypeInObjectLiterals.ts, 13, 6))
>n : Symbol(n, Decl(thisTypeInObjectLiterals.ts, 14, 9))
>sub1 : Symbol(sub1, Decl(thisTypeInObjectLiterals.ts, 17, 6))
>n : Symbol(n, Decl(thisTypeInObjectLiterals.ts, 18, 9))
if (n > 0) {
>n : Symbol(n, Decl(thisTypeInObjectLiterals.ts, 14, 9))
>n : Symbol(n, Decl(thisTypeInObjectLiterals.ts, 18, 9))
return this.passthrough(n - 1);
>this.passthrough : Symbol(passthrough, Decl(thisTypeInObjectLiterals.ts, 10, 6))
>this : Symbol(, Decl(thisTypeInObjectLiterals.ts, 6, 23))
>passthrough : Symbol(passthrough, Decl(thisTypeInObjectLiterals.ts, 10, 6))
>n : Symbol(n, Decl(thisTypeInObjectLiterals.ts, 14, 9))
>this.passthrough : Symbol(passthrough, Decl(thisTypeInObjectLiterals.ts, 14, 6))
>this : Symbol(, Decl(thisTypeInObjectLiterals.ts, 10, 23))
>passthrough : Symbol(passthrough, Decl(thisTypeInObjectLiterals.ts, 14, 6))
>n : Symbol(n, Decl(thisTypeInObjectLiterals.ts, 18, 9))
}
return n;
>n : Symbol(n, Decl(thisTypeInObjectLiterals.ts, 14, 9))
>n : Symbol(n, Decl(thisTypeInObjectLiterals.ts, 18, 9))
}
}
var i: number = mutuallyRecursive.start();
>i : Symbol(i, Decl(thisTypeInObjectLiterals.ts, 21, 3))
>mutuallyRecursive.start : Symbol(start, Decl(thisTypeInObjectLiterals.ts, 7, 11))
>mutuallyRecursive : Symbol(mutuallyRecursive, Decl(thisTypeInObjectLiterals.ts, 6, 3))
>start : Symbol(start, Decl(thisTypeInObjectLiterals.ts, 7, 11))
>i : Symbol(i, Decl(thisTypeInObjectLiterals.ts, 25, 3))
>mutuallyRecursive.start : Symbol(start, Decl(thisTypeInObjectLiterals.ts, 11, 11))
>mutuallyRecursive : Symbol(mutuallyRecursive, Decl(thisTypeInObjectLiterals.ts, 10, 3))
>start : Symbol(start, Decl(thisTypeInObjectLiterals.ts, 11, 11))
interface I {
>I : Symbol(I, Decl(thisTypeInObjectLiterals.ts, 21, 42))
>I : Symbol(I, Decl(thisTypeInObjectLiterals.ts, 25, 42))
a: number;
>a : Symbol(I.a, Decl(thisTypeInObjectLiterals.ts, 22, 13))
>a : Symbol(I.a, Decl(thisTypeInObjectLiterals.ts, 26, 13))
start(): number;
>start : Symbol(I.start, Decl(thisTypeInObjectLiterals.ts, 23, 14))
>start : Symbol(I.start, Decl(thisTypeInObjectLiterals.ts, 27, 14))
passthrough(n: number): number;
>passthrough : Symbol(I.passthrough, Decl(thisTypeInObjectLiterals.ts, 24, 20))
>n : Symbol(n, Decl(thisTypeInObjectLiterals.ts, 25, 16))
>passthrough : Symbol(I.passthrough, Decl(thisTypeInObjectLiterals.ts, 28, 20))
>n : Symbol(n, Decl(thisTypeInObjectLiterals.ts, 29, 16))
sub1(n: number): number;
>sub1 : Symbol(I.sub1, Decl(thisTypeInObjectLiterals.ts, 25, 35))
>n : Symbol(n, Decl(thisTypeInObjectLiterals.ts, 26, 9))
>sub1 : Symbol(I.sub1, Decl(thisTypeInObjectLiterals.ts, 29, 35))
>n : Symbol(n, Decl(thisTypeInObjectLiterals.ts, 30, 9))
}
var impl: I = mutuallyRecursive;
>impl : Symbol(impl, Decl(thisTypeInObjectLiterals.ts, 28, 3))
>I : Symbol(I, Decl(thisTypeInObjectLiterals.ts, 21, 42))
>mutuallyRecursive : Symbol(mutuallyRecursive, Decl(thisTypeInObjectLiterals.ts, 6, 3))
>impl : Symbol(impl, Decl(thisTypeInObjectLiterals.ts, 32, 3))
>I : Symbol(I, Decl(thisTypeInObjectLiterals.ts, 25, 42))
>mutuallyRecursive : Symbol(mutuallyRecursive, Decl(thisTypeInObjectLiterals.ts, 10, 3))
@@ -1,7 +1,7 @@
=== tests/cases/conformance/types/thisType/thisTypeInObjectLiterals.ts ===
let o = {
>o : { d: string; m(): number; }
>{ d: "bar", m() { return this.d.length; }} : { d: string; m(): number; }
>o : { d: string; m(): number; f: () => number; }
>{ d: "bar", m() { return this.d.length; }, f: function() { return this.d.length; }} : { d: string; m(): number; f: () => number; }
d: "bar",
>d : string
@@ -13,11 +13,24 @@ let o = {
return this.d.length;
>this.d.length : number
>this.d : string
>this : { d: string; m(): number; }
>this : { d: string; m(): number; f: () => number; }
>d : string
>length : number
},
f: function() {
>f : () => number
>function() { return this.d.length; } : () => number
return this.d.length;
>this.d.length : number
>this.d : string
>this : { d: string; m(): number; f: () => number; }
>d : string
>length : number
}
}
let mutuallyRecursive = {
>mutuallyRecursive : { a: number; start(): number; passthrough(n: number): number; sub1(n: number): number; }
>{ a: 100, start() { return this.passthrough(this.a); }, passthrough(n: number) { return this.sub1(n); }, sub1(n: number): number { if (n > 0) { return this.passthrough(n - 1); } return n; }} : { a: number; start(): number; passthrough(n: number): number; sub1(n: number): number; }
@@ -395,10 +395,16 @@ var buttonView = {
onClick: function () { alert('clicked: ' + this.label); },
>onClick : Symbol(onClick, Decl(underscoreTest1_underscoreTests.ts, 97, 24))
>alert : Symbol(alert, Decl(underscoreTest1_underscoreTests.ts, 2, 14))
>this.label : Symbol(label, Decl(underscoreTest1_underscoreTests.ts, 96, 18))
>this : Symbol(, Decl(underscoreTest1_underscoreTests.ts, 96, 16))
>label : Symbol(label, Decl(underscoreTest1_underscoreTests.ts, 96, 18))
onHover: function () { alert('hovering: ' + this.label); }
>onHover : Symbol(onHover, Decl(underscoreTest1_underscoreTests.ts, 98, 62))
>alert : Symbol(alert, Decl(underscoreTest1_underscoreTests.ts, 2, 14))
>this.label : Symbol(label, Decl(underscoreTest1_underscoreTests.ts, 96, 18))
>this : Symbol(, Decl(underscoreTest1_underscoreTests.ts, 96, 16))
>label : Symbol(label, Decl(underscoreTest1_underscoreTests.ts, 96, 18))
};
_.bindAll(buttonView);
@@ -827,9 +827,9 @@ var buttonView = {
>alert : (x: string) => void
>'clicked: ' + this.label : string
>'clicked: ' : string
>this.label : any
>this : any
>label : any
>this.label : string
>this : { label: string; onClick: () => void; onHover: () => void; }
>label : string
onHover: function () { alert('hovering: ' + this.label); }
>onHover : () => void
@@ -838,9 +838,9 @@ var buttonView = {
>alert : (x: string) => void
>'hovering: ' + this.label : string
>'hovering: ' : string
>this.label : any
>this : any
>label : any
>this.label : string
>this : { label: string; onClick: () => void; onHover: () => void; }
>label : string
};
_.bindAll(buttonView);
@@ -19,12 +19,12 @@ class C implements I {
}
let c = new C();
c.explicitVoid = c.explicitThis; // error, 'void' is missing everything
let o = {
let o = {
n: 101,
explicitThis: function (m: number) {
return m + this.n.length; // ok, this.n: any
explicitThis: function (m: number) {
return m + this.n.length; // error, 'length' does not exist on 'number'
},
implicitThis(m: number): number { return m; }
implicitThis(m: number): number { return m; }
};
let i: I = o;
let o2: I = {
@@ -44,4 +44,4 @@ o.implicitThis = c.explicitThis; // ok, implicitThis(this:any) is assignable to
o.implicitThis = i.explicitThis;
i.explicitThis = function(m) {
return this.n.length; // error, this.n: number
}
}
@@ -2,8 +2,12 @@ let o = {
d: "bar",
m() {
return this.d.length;
},
f: function() {
return this.d.length;
}
}
let mutuallyRecursive = {
a: 100,
start() {