Skip to content

Commit

Permalink
Merge pull request #14141 from Microsoft/contextualThisType
Browse files Browse the repository at this point in the history
Typed 'this' in object literal methods
  • Loading branch information
ahejlsberg authored Mar 6, 2017
2 parents 3295ca3 + 258bb4f commit 41226d0
Show file tree
Hide file tree
Showing 47 changed files with 2,574 additions and 394 deletions.
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 @@ -963,7 +965,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

0 comments on commit 41226d0

Please sign in to comment.