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

Typed 'this' in object literal methods #14141

Merged
merged 28 commits into from
Mar 6, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
f6a3a3f
Use '__this__' property in contextual type to indicate type of 'this'
ahejlsberg Feb 14, 2017
8cd6c5d
Introduce ThisType<T> marker interface
ahejlsberg Feb 17, 2017
2ca6164
Default contextual 'this' type is containing object literal
ahejlsberg Feb 17, 2017
e512376
Update tests
ahejlsberg Feb 17, 2017
d7e153d
Accept new baselines
ahejlsberg Feb 17, 2017
fe32bb7
Merge branch 'master' into contextualThisType
ahejlsberg Feb 17, 2017
27346b1
Accept new baselines
ahejlsberg Feb 17, 2017
e3a0687
Contextual this in 'obj.xxx = function(...)' or 'obj[xxx] = function(…
ahejlsberg Feb 17, 2017
168d367
Contextually type 'this' in accessors of object literals
ahejlsberg Feb 23, 2017
c2d8a59
Accept new baselines
ahejlsberg Feb 23, 2017
ec292c9
Update test
ahejlsberg Feb 23, 2017
9b6b6cc
Fix linting error
ahejlsberg Feb 23, 2017
9dc2bae
Use contextual type of object literal as 'this' in methods
ahejlsberg Feb 25, 2017
16f4030
Accept new baselines
ahejlsberg Feb 25, 2017
20b4523
Rename applyToContextualType to mapType and remove old mapType
ahejlsberg Feb 25, 2017
6fdd929
Update test
ahejlsberg Feb 25, 2017
cd87d90
Update comment
ahejlsberg Feb 27, 2017
5bda48b
Add tests
ahejlsberg Feb 27, 2017
993397b
Introduce CheckMode enum and getContextualMapper() function
ahejlsberg Feb 28, 2017
ff2cfd2
Update test
ahejlsberg Feb 28, 2017
c87c124
Accept new baselines
ahejlsberg Feb 28, 2017
ee7b93c
Merge branch 'master' into contextualThisType
ahejlsberg Feb 28, 2017
21c4300
Enable new behavior only in --noImplicitThis mode
ahejlsberg Mar 1, 2017
25738a8
Update tests
ahejlsberg Mar 1, 2017
f77cd8e
Accept new baselines
ahejlsberg Mar 1, 2017
9d1b325
Update another test
ahejlsberg Mar 1, 2017
7561cdf
Add ThisType<any> to Object.{create|defineProperty|defineProperties}
ahejlsberg Mar 2, 2017
258bb4f
Accept new baselines
ahejlsberg Mar 2, 2017
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
365 changes: 211 additions & 154 deletions src/compiler/checker.ts

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -519,6 +519,8 @@
/* @internal */ localSymbol?: Symbol; // Local symbol declared by node (initialized by binding only for exported nodes)
/* @internal */ flowNode?: FlowNode; // Associated FlowNode (initialized by binding)
/* @internal */ emitNode?: EmitNode; // Associated EmitNode (initialized by transforms)
/* @internal */ contextualType?: Type; // Used to temporarily assign a contextual type during overload resolution
/* @internal */ contextualMapper?: TypeMapper; // Mapper for contextual type
}

export interface NodeArray<T extends Node> extends Array<T>, TextRange {
Expand Down Expand Up @@ -957,7 +959,6 @@

export interface Expression extends Node {
_expressionBrand: any;
contextualType?: Type; // Used to temporarily assign a contextual type during overload resolution
}

export interface OmittedExpression extends Expression {
Expand Down
11 changes: 8 additions & 3 deletions src/lib/es5.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,22 +147,22 @@ interface ObjectConstructor {
* @param o Object to use as a prototype. May be null
* @param properties JavaScript object that contains one or more property descriptors.
*/
create(o: object | null, properties: PropertyDescriptorMap): any;
create(o: object | null, properties: PropertyDescriptorMap & ThisType<any>): any;

/**
* Adds a property to an object, or modifies attributes of an existing property.
* @param o Object on which to add or modify the property. This can be a native JavaScript object (that is, a user-defined object or a built in object) or a DOM object.
* @param p The property name.
* @param attributes Descriptor for the property. It can be for a data property or an accessor property.
*/
defineProperty(o: any, p: string, attributes: PropertyDescriptor): any;
defineProperty(o: any, p: string, attributes: PropertyDescriptor & ThisType<any>): any;

/**
* Adds one or more properties to an object, and/or modifies attributes of existing properties.
* @param o Object on which to add or modify the properties. This can be a native JavaScript object or a DOM object.
* @param properties JavaScript object that contains one or more descriptor objects. Each descriptor object describes a data property or an accessor property.
*/
defineProperties(o: any, properties: PropertyDescriptorMap): any;
defineProperties(o: any, properties: PropertyDescriptorMap & ThisType<any>): any;

/**
* Prevents the modification of attributes of existing properties, and prevents the addition of new properties.
Expand Down Expand Up @@ -1366,6 +1366,11 @@ type Record<K extends string, T> = {
[P in K]: T;
}

/**
* Marker for contextual 'this' type
*/
interface ThisType<T> { }

/**
* Represents a raw buffer of binary data, which is used to store data for the
* different typed arrays. ArrayBuffers cannot be read from or written to directly,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ tests/cases/conformance/declarationEmit/typePredicates/declarationEmitThisPredic
m(): this is Foo {
~~~~
!!! error TS2526: A 'this' type is available only in a non-static member of a class or interface.
let dis = this as Foo;
let dis = this as {} as Foo;
return dis.a != null && dis.b != null && dis.c != null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export interface Foo {

export const obj = {
m(): this is Foo {
let dis = this as Foo;
let dis = this as {} as Foo;
return dis.a != null && dis.b != null && dis.c != null;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ tests/cases/conformance/declarationEmit/typePredicates/declarationEmitThisPredic
m(): this is Foo {
~~~~
!!! error TS2526: A 'this' type is available only in a non-static member of a class or interface.
let dis = this as Foo;
let dis = this as {} as Foo;
return dis.a != null && dis.b != null && dis.c != null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ interface Foo {

export const obj = {
m(): this is Foo {
let dis = this as Foo;
let dis = this as {} as Foo;
return dis.a != null && dis.b != null && dis.c != null;
}
}
Expand Down
4 changes: 2 additions & 2 deletions tests/baselines/reference/getterSetterNonAccessor.types
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ function setFunc(v){}

Object.defineProperty({}, "0", <PropertyDescriptor>({
>Object.defineProperty({}, "0", <PropertyDescriptor>({ get: getFunc, set: setFunc, configurable: true })) : any
>Object.defineProperty : (o: any, p: string, attributes: PropertyDescriptor) => any
>Object.defineProperty : (o: any, p: string, attributes: PropertyDescriptor & ThisType<any>) => any
>Object : ObjectConstructor
>defineProperty : (o: any, p: string, attributes: PropertyDescriptor) => any
>defineProperty : (o: any, p: string, attributes: PropertyDescriptor & ThisType<any>) => any
>{} : {}
>"0" : "0"
><PropertyDescriptor>({ get: getFunc, set: setFunc, configurable: true }) : PropertyDescriptor
Expand Down
14 changes: 9 additions & 5 deletions tests/baselines/reference/looseThisTypeInFunctions.errors.txt
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
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'.
tests/cases/conformance/types/thisType/looseThisTypeInFunctions.ts(22,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(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(26,27): error TS2339: Property 'length' does not exist on type 'number'.
tests/cases/conformance/types/thisType/looseThisTypeInFunctions.ts(34,28): error TS2339: Property 'length' does not exist on type 'number'.
tests/cases/conformance/types/thisType/looseThisTypeInFunctions.ts(38,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(47,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;
Expand Down Expand Up @@ -36,6 +38,8 @@ tests/cases/conformance/types/thisType/looseThisTypeInFunctions.ts(46,20): error
n: 101,
explicitThis: function (m: number) {
return m + this.n.length; // error, 'length' does not exist on 'number'
~~~~~~
!!! error TS2339: Property 'length' does not exist on type 'number'.
},
implicitThis(m: number): number { return m; }
};
Expand Down
1 change: 1 addition & 0 deletions tests/baselines/reference/looseThisTypeInFunctions.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
//// [looseThisTypeInFunctions.ts]

interface I {
n: number;
explicitThis(this: this, m: number): number;
Expand Down
40 changes: 20 additions & 20 deletions tests/baselines/reference/objectCreate.types
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,17 @@ declare var union: null | { a: number, b: string };
var n = Object.create(null); // object
>n : any
>Object.create(null) : any
>Object.create : { (o: object | null): any; (o: object | null, properties: PropertyDescriptorMap): any; }
>Object.create : { (o: object | null): any; (o: object | null, properties: PropertyDescriptorMap & ThisType<any>): any; }
>Object : ObjectConstructor
>create : { (o: object | null): any; (o: object | null, properties: PropertyDescriptorMap): any; }
>create : { (o: object | null): any; (o: object | null, properties: PropertyDescriptorMap & ThisType<any>): any; }
>null : null

var t = Object.create({ a: 1, b: "" }); // {a: number, b: string }
>t : any
>Object.create({ a: 1, b: "" }) : any
>Object.create : { (o: object | null): any; (o: object | null, properties: PropertyDescriptorMap): any; }
>Object.create : { (o: object | null): any; (o: object | null, properties: PropertyDescriptorMap & ThisType<any>): any; }
>Object : ObjectConstructor
>create : { (o: object | null): any; (o: object | null, properties: PropertyDescriptorMap): any; }
>create : { (o: object | null): any; (o: object | null, properties: PropertyDescriptorMap & ThisType<any>): any; }
>{ a: 1, b: "" } : { a: number; b: string; }
>a : number
>1 : 1
Expand All @@ -29,43 +29,43 @@ var t = Object.create({ a: 1, b: "" }); // {a: number, b: string }
var u = Object.create(union); // object | {a: number, b: string }
>u : any
>Object.create(union) : any
>Object.create : { (o: object | null): any; (o: object | null, properties: PropertyDescriptorMap): any; }
>Object.create : { (o: object | null): any; (o: object | null, properties: PropertyDescriptorMap & ThisType<any>): any; }
>Object : ObjectConstructor
>create : { (o: object | null): any; (o: object | null, properties: PropertyDescriptorMap): any; }
>create : { (o: object | null): any; (o: object | null, properties: PropertyDescriptorMap & ThisType<any>): any; }
>union : { a: number; b: string; } | null

var e = Object.create({}); // {}
>e : any
>Object.create({}) : any
>Object.create : { (o: object | null): any; (o: object | null, properties: PropertyDescriptorMap): any; }
>Object.create : { (o: object | null): any; (o: object | null, properties: PropertyDescriptorMap & ThisType<any>): any; }
>Object : ObjectConstructor
>create : { (o: object | null): any; (o: object | null, properties: PropertyDescriptorMap): any; }
>create : { (o: object | null): any; (o: object | null, properties: PropertyDescriptorMap & ThisType<any>): any; }
>{} : {}

var o = Object.create(<object>{}); // object
>o : any
>Object.create(<object>{}) : any
>Object.create : { (o: object | null): any; (o: object | null, properties: PropertyDescriptorMap): any; }
>Object.create : { (o: object | null): any; (o: object | null, properties: PropertyDescriptorMap & ThisType<any>): any; }
>Object : ObjectConstructor
>create : { (o: object | null): any; (o: object | null, properties: PropertyDescriptorMap): any; }
>create : { (o: object | null): any; (o: object | null, properties: PropertyDescriptorMap & ThisType<any>): any; }
><object>{} : object
>{} : {}

var a = Object.create(null, {}); // any
>a : any
>Object.create(null, {}) : any
>Object.create : { (o: object | null): any; (o: object | null, properties: PropertyDescriptorMap): any; }
>Object.create : { (o: object | null): any; (o: object | null, properties: PropertyDescriptorMap & ThisType<any>): any; }
>Object : ObjectConstructor
>create : { (o: object | null): any; (o: object | null, properties: PropertyDescriptorMap): any; }
>create : { (o: object | null): any; (o: object | null, properties: PropertyDescriptorMap & ThisType<any>): any; }
>null : null
>{} : {}

var a = Object.create({ a: 1, b: "" }, {});
>a : any
>Object.create({ a: 1, b: "" }, {}) : any
>Object.create : { (o: object | null): any; (o: object | null, properties: PropertyDescriptorMap): any; }
>Object.create : { (o: object | null): any; (o: object | null, properties: PropertyDescriptorMap & ThisType<any>): any; }
>Object : ObjectConstructor
>create : { (o: object | null): any; (o: object | null, properties: PropertyDescriptorMap): any; }
>create : { (o: object | null): any; (o: object | null, properties: PropertyDescriptorMap & ThisType<any>): any; }
>{ a: 1, b: "" } : { a: number; b: string; }
>a : number
>1 : 1
Expand All @@ -76,27 +76,27 @@ var a = Object.create({ a: 1, b: "" }, {});
var a = Object.create(union, {});
>a : any
>Object.create(union, {}) : any
>Object.create : { (o: object | null): any; (o: object | null, properties: PropertyDescriptorMap): any; }
>Object.create : { (o: object | null): any; (o: object | null, properties: PropertyDescriptorMap & ThisType<any>): any; }
>Object : ObjectConstructor
>create : { (o: object | null): any; (o: object | null, properties: PropertyDescriptorMap): any; }
>create : { (o: object | null): any; (o: object | null, properties: PropertyDescriptorMap & ThisType<any>): any; }
>union : { a: number; b: string; } | null
>{} : {}

var a = Object.create({}, {});
>a : any
>Object.create({}, {}) : any
>Object.create : { (o: object | null): any; (o: object | null, properties: PropertyDescriptorMap): any; }
>Object.create : { (o: object | null): any; (o: object | null, properties: PropertyDescriptorMap & ThisType<any>): any; }
>Object : ObjectConstructor
>create : { (o: object | null): any; (o: object | null, properties: PropertyDescriptorMap): any; }
>create : { (o: object | null): any; (o: object | null, properties: PropertyDescriptorMap & ThisType<any>): any; }
>{} : {}
>{} : {}

var a = Object.create(<object>{}, {});
>a : any
>Object.create(<object>{}, {}) : any
>Object.create : { (o: object | null): any; (o: object | null, properties: PropertyDescriptorMap): any; }
>Object.create : { (o: object | null): any; (o: object | null, properties: PropertyDescriptorMap & ThisType<any>): any; }
>Object : ObjectConstructor
>create : { (o: object | null): any; (o: object | null, properties: PropertyDescriptorMap): any; }
>create : { (o: object | null): any; (o: object | null, properties: PropertyDescriptorMap & ThisType<any>): any; }
><object>{} : object
>{} : {}
>{} : {}
Expand Down
40 changes: 20 additions & 20 deletions tests/baselines/reference/objectCreate2.types
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,17 @@ declare var union: null | { a: number, b: string };
var n = Object.create(null); // any
>n : any
>Object.create(null) : any
>Object.create : { (o: object): any; (o: object, properties: PropertyDescriptorMap): any; }
>Object.create : { (o: object): any; (o: object, properties: PropertyDescriptorMap & ThisType<any>): any; }
>Object : ObjectConstructor
>create : { (o: object): any; (o: object, properties: PropertyDescriptorMap): any; }
>create : { (o: object): any; (o: object, properties: PropertyDescriptorMap & ThisType<any>): any; }
>null : null

var t = Object.create({ a: 1, b: "" }); // {a: number, b: string }
>t : any
>Object.create({ a: 1, b: "" }) : any
>Object.create : { (o: object): any; (o: object, properties: PropertyDescriptorMap): any; }
>Object.create : { (o: object): any; (o: object, properties: PropertyDescriptorMap & ThisType<any>): any; }
>Object : ObjectConstructor
>create : { (o: object): any; (o: object, properties: PropertyDescriptorMap): any; }
>create : { (o: object): any; (o: object, properties: PropertyDescriptorMap & ThisType<any>): any; }
>{ a: 1, b: "" } : { a: number; b: string; }
>a : number
>1 : 1
Expand All @@ -29,43 +29,43 @@ var t = Object.create({ a: 1, b: "" }); // {a: number, b: string }
var u = Object.create(union); // {a: number, b: string }
>u : any
>Object.create(union) : any
>Object.create : { (o: object): any; (o: object, properties: PropertyDescriptorMap): any; }
>Object.create : { (o: object): any; (o: object, properties: PropertyDescriptorMap & ThisType<any>): any; }
>Object : ObjectConstructor
>create : { (o: object): any; (o: object, properties: PropertyDescriptorMap): any; }
>create : { (o: object): any; (o: object, properties: PropertyDescriptorMap & ThisType<any>): any; }
>union : { a: number; b: string; }

var e = Object.create({}); // {}
>e : any
>Object.create({}) : any
>Object.create : { (o: object): any; (o: object, properties: PropertyDescriptorMap): any; }
>Object.create : { (o: object): any; (o: object, properties: PropertyDescriptorMap & ThisType<any>): any; }
>Object : ObjectConstructor
>create : { (o: object): any; (o: object, properties: PropertyDescriptorMap): any; }
>create : { (o: object): any; (o: object, properties: PropertyDescriptorMap & ThisType<any>): any; }
>{} : {}

var o = Object.create(<object>{}); // object
>o : any
>Object.create(<object>{}) : any
>Object.create : { (o: object): any; (o: object, properties: PropertyDescriptorMap): any; }
>Object.create : { (o: object): any; (o: object, properties: PropertyDescriptorMap & ThisType<any>): any; }
>Object : ObjectConstructor
>create : { (o: object): any; (o: object, properties: PropertyDescriptorMap): any; }
>create : { (o: object): any; (o: object, properties: PropertyDescriptorMap & ThisType<any>): any; }
><object>{} : object
>{} : {}

var a = Object.create(null, {}); // any
>a : any
>Object.create(null, {}) : any
>Object.create : { (o: object): any; (o: object, properties: PropertyDescriptorMap): any; }
>Object.create : { (o: object): any; (o: object, properties: PropertyDescriptorMap & ThisType<any>): any; }
>Object : ObjectConstructor
>create : { (o: object): any; (o: object, properties: PropertyDescriptorMap): any; }
>create : { (o: object): any; (o: object, properties: PropertyDescriptorMap & ThisType<any>): any; }
>null : null
>{} : {}

var a = Object.create({ a: 1, b: "" }, {});
>a : any
>Object.create({ a: 1, b: "" }, {}) : any
>Object.create : { (o: object): any; (o: object, properties: PropertyDescriptorMap): any; }
>Object.create : { (o: object): any; (o: object, properties: PropertyDescriptorMap & ThisType<any>): any; }
>Object : ObjectConstructor
>create : { (o: object): any; (o: object, properties: PropertyDescriptorMap): any; }
>create : { (o: object): any; (o: object, properties: PropertyDescriptorMap & ThisType<any>): any; }
>{ a: 1, b: "" } : { a: number; b: string; }
>a : number
>1 : 1
Expand All @@ -76,27 +76,27 @@ var a = Object.create({ a: 1, b: "" }, {});
var a = Object.create(union, {});
>a : any
>Object.create(union, {}) : any
>Object.create : { (o: object): any; (o: object, properties: PropertyDescriptorMap): any; }
>Object.create : { (o: object): any; (o: object, properties: PropertyDescriptorMap & ThisType<any>): any; }
>Object : ObjectConstructor
>create : { (o: object): any; (o: object, properties: PropertyDescriptorMap): any; }
>create : { (o: object): any; (o: object, properties: PropertyDescriptorMap & ThisType<any>): any; }
>union : { a: number; b: string; }
>{} : {}

var a = Object.create({}, {});
>a : any
>Object.create({}, {}) : any
>Object.create : { (o: object): any; (o: object, properties: PropertyDescriptorMap): any; }
>Object.create : { (o: object): any; (o: object, properties: PropertyDescriptorMap & ThisType<any>): any; }
>Object : ObjectConstructor
>create : { (o: object): any; (o: object, properties: PropertyDescriptorMap): any; }
>create : { (o: object): any; (o: object, properties: PropertyDescriptorMap & ThisType<any>): any; }
>{} : {}
>{} : {}

var a = Object.create(<object>{}, {});
>a : any
>Object.create(<object>{}, {}) : any
>Object.create : { (o: object): any; (o: object, properties: PropertyDescriptorMap): any; }
>Object.create : { (o: object): any; (o: object, properties: PropertyDescriptorMap & ThisType<any>): any; }
>Object : ObjectConstructor
>create : { (o: object): any; (o: object, properties: PropertyDescriptorMap): any; }
>create : { (o: object): any; (o: object, properties: PropertyDescriptorMap & ThisType<any>): any; }
><object>{} : object
>{} : {}
>{} : {}
Expand Down
Loading