From 973ded23e3415e2bae9bb88a868c794dd6c512d2 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Thu, 17 Jan 2019 14:39:05 -0800 Subject: [PATCH 1/2] Instantiate `this` in non-super property/element access expressions --- src/compiler/checker.ts | 3 ++ .../reference/chainedThisRefinements.js | 34 +++++++++++++ .../reference/chainedThisRefinements.symbols | 50 +++++++++++++++++++ .../reference/chainedThisRefinements.types | 50 +++++++++++++++++++ ...teClassPropertyAccessibleWithinClass.types | 2 +- ...sPropertyAccessibleWithinNestedClass.types | 2 +- ...edClassPropertyAccessibleWithinClass.types | 2 +- ...sPropertyAccessibleWithinNestedClass.types | 2 +- .../reference/recursiveFunctionTypes.types | 2 +- .../reference/recursiveFunctionTypes1.types | 2 +- .../thisTypeInFunctionsNegative.errors.txt | 4 ++ .../cases/compiler/chainedThisRefinements.ts | 15 ++++++ 12 files changed, 162 insertions(+), 6 deletions(-) create mode 100644 tests/baselines/reference/chainedThisRefinements.js create mode 100644 tests/baselines/reference/chainedThisRefinements.symbols create mode 100644 tests/baselines/reference/chainedThisRefinements.types create mode 100644 tests/cases/compiler/chainedThisRefinements.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 282765dcc7b1d..214c8b9cacc79 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -19198,6 +19198,9 @@ namespace ts { } propType = getConstraintForLocation(getTypeOfSymbol(prop), node); } + // Instantiate `this` in the property with the type of the thing being accessed - excepting `super` accesses where, despite + // the syntax, the `this` in the access will be the original one instead. + propType = left.kind !== SyntaxKind.SuperKeyword ? instantiateType(propType, t => t.isThisType ? leftType : t) : propType; // Only compute control flow type if this is a property access expression that isn't an // assignment target, and the referenced property was declared as a variable, property, // accessor, or optional method. diff --git a/tests/baselines/reference/chainedThisRefinements.js b/tests/baselines/reference/chainedThisRefinements.js new file mode 100644 index 0000000000000..b537f03c7f2f0 --- /dev/null +++ b/tests/baselines/reference/chainedThisRefinements.js @@ -0,0 +1,34 @@ +//// [chainedThisRefinements.ts] +class Builder { + private _class: undefined; + withFoo() { + return this as this & { foo: T } + } + withBar() { + return this as this & { bar: T } + } + withFooBar() { + return this.withFoo().withBar(); + } +} + +declare var f: {foo: number}; +f = new Builder().withFooBar(); // should work + + +//// [chainedThisRefinements.js] +var Builder = /** @class */ (function () { + function Builder() { + } + Builder.prototype.withFoo = function () { + return this; + }; + Builder.prototype.withBar = function () { + return this; + }; + Builder.prototype.withFooBar = function () { + return this.withFoo().withBar(); + }; + return Builder; +}()); +f = new Builder().withFooBar(); // should work diff --git a/tests/baselines/reference/chainedThisRefinements.symbols b/tests/baselines/reference/chainedThisRefinements.symbols new file mode 100644 index 0000000000000..d16a1e4afd169 --- /dev/null +++ b/tests/baselines/reference/chainedThisRefinements.symbols @@ -0,0 +1,50 @@ +=== tests/cases/compiler/chainedThisRefinements.ts === +class Builder { +>Builder : Symbol(Builder, Decl(chainedThisRefinements.ts, 0, 0)) + + private _class: undefined; +>_class : Symbol(Builder._class, Decl(chainedThisRefinements.ts, 0, 15)) + + withFoo() { +>withFoo : Symbol(Builder.withFoo, Decl(chainedThisRefinements.ts, 1, 30)) +>T : Symbol(T, Decl(chainedThisRefinements.ts, 2, 12)) + + return this as this & { foo: T } +>this : Symbol(Builder, Decl(chainedThisRefinements.ts, 0, 0)) +>foo : Symbol(foo, Decl(chainedThisRefinements.ts, 3, 31)) +>T : Symbol(T, Decl(chainedThisRefinements.ts, 2, 12)) + } + withBar() { +>withBar : Symbol(Builder.withBar, Decl(chainedThisRefinements.ts, 4, 5)) +>T : Symbol(T, Decl(chainedThisRefinements.ts, 5, 12)) + + return this as this & { bar: T } +>this : Symbol(Builder, Decl(chainedThisRefinements.ts, 0, 0)) +>bar : Symbol(bar, Decl(chainedThisRefinements.ts, 6, 31)) +>T : Symbol(T, Decl(chainedThisRefinements.ts, 5, 12)) + } + withFooBar() { +>withFooBar : Symbol(Builder.withFooBar, Decl(chainedThisRefinements.ts, 7, 5)) +>T : Symbol(T, Decl(chainedThisRefinements.ts, 8, 15)) + + return this.withFoo().withBar(); +>this.withFoo().withBar : Symbol(Builder.withBar, Decl(chainedThisRefinements.ts, 4, 5)) +>this.withFoo : Symbol(Builder.withFoo, Decl(chainedThisRefinements.ts, 1, 30)) +>this : Symbol(Builder, Decl(chainedThisRefinements.ts, 0, 0)) +>withFoo : Symbol(Builder.withFoo, Decl(chainedThisRefinements.ts, 1, 30)) +>T : Symbol(T, Decl(chainedThisRefinements.ts, 8, 15)) +>withBar : Symbol(Builder.withBar, Decl(chainedThisRefinements.ts, 4, 5)) +>T : Symbol(T, Decl(chainedThisRefinements.ts, 8, 15)) + } +} + +declare var f: {foo: number}; +>f : Symbol(f, Decl(chainedThisRefinements.ts, 13, 11)) +>foo : Symbol(foo, Decl(chainedThisRefinements.ts, 13, 16)) + +f = new Builder().withFooBar(); // should work +>f : Symbol(f, Decl(chainedThisRefinements.ts, 13, 11)) +>new Builder().withFooBar : Symbol(Builder.withFooBar, Decl(chainedThisRefinements.ts, 7, 5)) +>Builder : Symbol(Builder, Decl(chainedThisRefinements.ts, 0, 0)) +>withFooBar : Symbol(Builder.withFooBar, Decl(chainedThisRefinements.ts, 7, 5)) + diff --git a/tests/baselines/reference/chainedThisRefinements.types b/tests/baselines/reference/chainedThisRefinements.types new file mode 100644 index 0000000000000..6d6cfac9dd2c7 --- /dev/null +++ b/tests/baselines/reference/chainedThisRefinements.types @@ -0,0 +1,50 @@ +=== tests/cases/compiler/chainedThisRefinements.ts === +class Builder { +>Builder : Builder + + private _class: undefined; +>_class : undefined + + withFoo() { +>withFoo : () => this & { foo: T; } + + return this as this & { foo: T } +>this as this & { foo: T } : this & { foo: T; } +>this : this +>foo : T + } + withBar() { +>withBar : () => this & { bar: T; } + + return this as this & { bar: T } +>this as this & { bar: T } : this & { bar: T; } +>this : this +>bar : T + } + withFooBar() { +>withFooBar : () => this & { foo: T; } & { bar: T; } + + return this.withFoo().withBar(); +>this.withFoo().withBar() : this & { foo: T; } & { bar: T; } +>this.withFoo().withBar : () => this & { foo: T; } & { bar: T; } +>this.withFoo() : this & { foo: T; } +>this.withFoo : () => this & { foo: T; } +>this : this +>withFoo : () => this & { foo: T; } +>withBar : () => this & { foo: T; } & { bar: T; } + } +} + +declare var f: {foo: number}; +>f : { foo: number; } +>foo : number + +f = new Builder().withFooBar(); // should work +>f = new Builder().withFooBar() : Builder & { foo: number; } & { bar: number; } +>f : { foo: number; } +>new Builder().withFooBar() : Builder & { foo: number; } & { bar: number; } +>new Builder().withFooBar : () => Builder & { foo: T; } & { bar: T; } +>new Builder() : Builder +>Builder : typeof Builder +>withFooBar : () => Builder & { foo: T; } & { bar: T; } + diff --git a/tests/baselines/reference/privateClassPropertyAccessibleWithinClass.types b/tests/baselines/reference/privateClassPropertyAccessibleWithinClass.types index 56aedbe253545..5286db36a8f1f 100644 --- a/tests/baselines/reference/privateClassPropertyAccessibleWithinClass.types +++ b/tests/baselines/reference/privateClassPropertyAccessibleWithinClass.types @@ -51,7 +51,7 @@ class C { >x : string private static foo() { return this.foo; } ->foo : () => typeof C.foo +>foo : () => () => typeof C.foo >this.foo : () => typeof C.foo >this : typeof C >foo : () => typeof C.foo diff --git a/tests/baselines/reference/privateClassPropertyAccessibleWithinNestedClass.types b/tests/baselines/reference/privateClassPropertyAccessibleWithinNestedClass.types index c5338b68c41e5..9a6b1130748b8 100644 --- a/tests/baselines/reference/privateClassPropertyAccessibleWithinNestedClass.types +++ b/tests/baselines/reference/privateClassPropertyAccessibleWithinNestedClass.types @@ -51,7 +51,7 @@ class C { >x : string private static foo() { return this.foo; } ->foo : () => typeof C.foo +>foo : () => () => typeof C.foo >this.foo : () => typeof C.foo >this : typeof C >foo : () => typeof C.foo diff --git a/tests/baselines/reference/protectedClassPropertyAccessibleWithinClass.types b/tests/baselines/reference/protectedClassPropertyAccessibleWithinClass.types index 1e325d1d6f5e1..5130416b98528 100644 --- a/tests/baselines/reference/protectedClassPropertyAccessibleWithinClass.types +++ b/tests/baselines/reference/protectedClassPropertyAccessibleWithinClass.types @@ -51,7 +51,7 @@ class C { >x : string protected static foo() { return this.foo; } ->foo : () => typeof C.foo +>foo : () => () => typeof C.foo >this.foo : () => typeof C.foo >this : typeof C >foo : () => typeof C.foo diff --git a/tests/baselines/reference/protectedClassPropertyAccessibleWithinNestedClass.types b/tests/baselines/reference/protectedClassPropertyAccessibleWithinNestedClass.types index 6b6bf6edfc9fb..39987a615e76f 100644 --- a/tests/baselines/reference/protectedClassPropertyAccessibleWithinNestedClass.types +++ b/tests/baselines/reference/protectedClassPropertyAccessibleWithinNestedClass.types @@ -51,7 +51,7 @@ class C { >x : string protected static foo() { return this.foo; } ->foo : () => typeof C.foo +>foo : () => () => typeof C.foo >this.foo : () => typeof C.foo >this : typeof C >foo : () => typeof C.foo diff --git a/tests/baselines/reference/recursiveFunctionTypes.types b/tests/baselines/reference/recursiveFunctionTypes.types index 72ba77b48f6f9..d3f2f84574d68 100644 --- a/tests/baselines/reference/recursiveFunctionTypes.types +++ b/tests/baselines/reference/recursiveFunctionTypes.types @@ -47,7 +47,7 @@ class C { >C : C static g(t: typeof C.g){ } ->g : (t: typeof C.g) => void +>g : (t: (t: typeof C.g) => void) => void >t : (t: typeof C.g) => void >C.g : (t: typeof C.g) => void >C : typeof C diff --git a/tests/baselines/reference/recursiveFunctionTypes1.types b/tests/baselines/reference/recursiveFunctionTypes1.types index 52cf90f1059d4..9026196682e4c 100644 --- a/tests/baselines/reference/recursiveFunctionTypes1.types +++ b/tests/baselines/reference/recursiveFunctionTypes1.types @@ -3,7 +3,7 @@ class C { >C : C static g(t: typeof C.g){ } ->g : (t: typeof C.g) => void +>g : (t: (t: typeof C.g) => void) => void >t : (t: typeof C.g) => void >C.g : (t: typeof C.g) => void >C : typeof C diff --git a/tests/baselines/reference/thisTypeInFunctionsNegative.errors.txt b/tests/baselines/reference/thisTypeInFunctionsNegative.errors.txt index 9222b23d4f1dd..428ea42e6d056 100644 --- a/tests/baselines/reference/thisTypeInFunctionsNegative.errors.txt +++ b/tests/baselines/reference/thisTypeInFunctionsNegative.errors.txt @@ -69,6 +69,8 @@ tests/cases/conformance/types/thisType/thisTypeInFunctionsNegative.ts(146,1): er The 'this' types of each signature are incompatible. Type 'Base1' is not assignable to type 'Base2'. tests/cases/conformance/types/thisType/thisTypeInFunctionsNegative.ts(148,1): error TS2322: Type '(this: Base2) => number' is not assignable to type '(this: Base1) => number'. + The 'this' types of each signature are incompatible. + Type 'Base1' is not assignable to type 'Base2'. tests/cases/conformance/types/thisType/thisTypeInFunctionsNegative.ts(154,16): error TS2679: A function that is called with the 'new' keyword cannot have a 'this' type that is 'void'. tests/cases/conformance/types/thisType/thisTypeInFunctionsNegative.ts(158,17): error TS2681: A constructor cannot have a 'this' parameter. tests/cases/conformance/types/thisType/thisTypeInFunctionsNegative.ts(162,9): error TS2681: A constructor cannot have a 'this' parameter. @@ -364,6 +366,8 @@ tests/cases/conformance/types/thisType/thisTypeInFunctionsNegative.ts(178,22): e d1.explicit = b2.polymorphic // error, 'y' not in Base1: { x } ~~~~~~~~~~~ !!! error TS2322: Type '(this: Base2) => number' is not assignable to type '(this: Base1) => number'. +!!! error TS2322: The 'this' types of each signature are incompatible. +!!! error TS2322: Type 'Base1' is not assignable to type 'Base2'. ////// use this-type for construction with new //// function VoidThis(this: void) { diff --git a/tests/cases/compiler/chainedThisRefinements.ts b/tests/cases/compiler/chainedThisRefinements.ts new file mode 100644 index 0000000000000..78eb1db232452 --- /dev/null +++ b/tests/cases/compiler/chainedThisRefinements.ts @@ -0,0 +1,15 @@ +class Builder { + private _class: undefined; + withFoo() { + return this as this & { foo: T } + } + withBar() { + return this as this & { bar: T } + } + withFooBar() { + return this.withFoo().withBar(); + } +} + +declare var f: {foo: number}; +f = new Builder().withFooBar(); // should work From 7c14e3494ecbe5b02ea30e78f94acac5cef20486 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Fri, 18 Jan 2019 17:17:23 -0800 Subject: [PATCH 2/2] Instantiate this indirectly via this-reference reinstantiation --- src/compiler/checker.ts | 23 ++++- .../reference/chainedThisRefinements.js | 18 +++- .../reference/chainedThisRefinements.symbols | 70 ++++++++++++++- .../reference/chainedThisRefinements.types | 86 +++++++++++++++++-- ...teClassPropertyAccessibleWithinClass.types | 2 +- ...sPropertyAccessibleWithinNestedClass.types | 2 +- ...edClassPropertyAccessibleWithinClass.types | 2 +- ...sPropertyAccessibleWithinNestedClass.types | 2 +- .../reference/recursiveFunctionTypes.types | 2 +- .../reference/recursiveFunctionTypes1.types | 2 +- .../thisTypeInFunctionsNegative.errors.txt | 4 - .../cases/compiler/chainedThisRefinements.ts | 9 +- 12 files changed, 197 insertions(+), 25 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 214c8b9cacc79..c85414fbcef0d 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -6631,6 +6631,9 @@ namespace ts { else if (type.flags & TypeFlags.Intersection) { return getIntersectionType(map((type).types, t => getTypeWithThisArgument(t, thisArgument, needApparentType))); } + else if (type.flags & TypeFlags.TypeParameter && thisArgument && (type as TypeParameter).isThisType) { + return getTypeWithThisArgument(createTypeReference(globalThisType, [type]), needApparentType ? instantiateType(thisArgument, createTypeMapper([type], [getApparentType(type)])) : thisArgument, needApparentType); + } return needApparentType ? getApparentType(type) : type; } @@ -6685,6 +6688,23 @@ namespace ts { } function resolveTypeReferenceMembers(type: TypeReference): void { + + if (type.target === globalThisType && type.typeArguments && type.typeArguments[0].flags & TypeFlags.TypeParameter && + (type.typeArguments[0] as TypeParameter).isThisType && type.typeArguments[1]) { + if (type.typeArguments[1].flags & TypeFlags.StructuredType) { + const instantiatedTarget = instantiateType(type.typeArguments[1], createTypeMapper([type.typeArguments[0]], [type.typeArguments[1]])); + const props = getPropertiesOfType(instantiatedTarget); + const calls = getSignaturesOfType(instantiatedTarget, SignatureKind.Call); + const ctors = getSignaturesOfType(instantiatedTarget, SignatureKind.Construct); + const strIndex = getIndexInfoOfType(instantiatedTarget, IndexKind.String); + const numIndex = getIndexInfoOfType(instantiatedTarget, IndexKind.Number); + setStructuredTypeMembers(type, createMapFromEntries(props.map(p => [p.escapedName, p]) as [string, Symbol][]) as SymbolTable, calls, ctors, strIndex, numIndex); + } + else { + setStructuredTypeMembers(type, emptySymbols, emptyArray, emptyArray, /*stringIndexInfo*/ undefined, /*numberIndexInfo*/ undefined); + } + return; + } const source = resolveDeclaredMembers(type.target); const typeParameters = concatenate(source.typeParameters!, [source.thisType!]); const typeArguments = type.typeArguments && type.typeArguments.length === typeParameters.length ? @@ -19198,9 +19218,6 @@ namespace ts { } propType = getConstraintForLocation(getTypeOfSymbol(prop), node); } - // Instantiate `this` in the property with the type of the thing being accessed - excepting `super` accesses where, despite - // the syntax, the `this` in the access will be the original one instead. - propType = left.kind !== SyntaxKind.SuperKeyword ? instantiateType(propType, t => t.isThisType ? leftType : t) : propType; // Only compute control flow type if this is a property access expression that isn't an // assignment target, and the referenced property was declared as a variable, property, // accessor, or optional method. diff --git a/tests/baselines/reference/chainedThisRefinements.js b/tests/baselines/reference/chainedThisRefinements.js index b537f03c7f2f0..ca743711b421b 100644 --- a/tests/baselines/reference/chainedThisRefinements.js +++ b/tests/baselines/reference/chainedThisRefinements.js @@ -8,12 +8,19 @@ class Builder { return this as this & { bar: T } } withFooBar() { + this.withFoo().withBar().foo; + this.withFoo().withBar().bar; return this.withFoo().withBar(); } } declare var f: {foo: number}; -f = new Builder().withFooBar(); // should work +new Builder().withFoo().withBar().foo; +new Builder().withFoo().withBar().bar; +f = new Builder().withFoo().withBar(); +new Builder().withFooBar().foo; +new Builder().withFooBar().bar; +f = new Builder().withFooBar(); //// [chainedThisRefinements.js] @@ -27,8 +34,15 @@ var Builder = /** @class */ (function () { return this; }; Builder.prototype.withFooBar = function () { + this.withFoo().withBar().foo; + this.withFoo().withBar().bar; return this.withFoo().withBar(); }; return Builder; }()); -f = new Builder().withFooBar(); // should work +new Builder().withFoo().withBar().foo; +new Builder().withFoo().withBar().bar; +f = new Builder().withFoo().withBar(); +new Builder().withFooBar().foo; +new Builder().withFooBar().bar; +f = new Builder().withFooBar(); diff --git a/tests/baselines/reference/chainedThisRefinements.symbols b/tests/baselines/reference/chainedThisRefinements.symbols index d16a1e4afd169..668fd977418f7 100644 --- a/tests/baselines/reference/chainedThisRefinements.symbols +++ b/tests/baselines/reference/chainedThisRefinements.symbols @@ -27,6 +27,28 @@ class Builder { >withFooBar : Symbol(Builder.withFooBar, Decl(chainedThisRefinements.ts, 7, 5)) >T : Symbol(T, Decl(chainedThisRefinements.ts, 8, 15)) + this.withFoo().withBar().foo; +>this.withFoo().withBar().foo : Symbol(foo, Decl(chainedThisRefinements.ts, 3, 31)) +>this.withFoo().withBar : Symbol(Builder.withBar, Decl(chainedThisRefinements.ts, 4, 5)) +>this.withFoo : Symbol(Builder.withFoo, Decl(chainedThisRefinements.ts, 1, 30)) +>this : Symbol(Builder, Decl(chainedThisRefinements.ts, 0, 0)) +>withFoo : Symbol(Builder.withFoo, Decl(chainedThisRefinements.ts, 1, 30)) +>T : Symbol(T, Decl(chainedThisRefinements.ts, 8, 15)) +>withBar : Symbol(Builder.withBar, Decl(chainedThisRefinements.ts, 4, 5)) +>T : Symbol(T, Decl(chainedThisRefinements.ts, 8, 15)) +>foo : Symbol(foo, Decl(chainedThisRefinements.ts, 3, 31)) + + this.withFoo().withBar().bar; +>this.withFoo().withBar().bar : Symbol(bar, Decl(chainedThisRefinements.ts, 6, 31)) +>this.withFoo().withBar : Symbol(Builder.withBar, Decl(chainedThisRefinements.ts, 4, 5)) +>this.withFoo : Symbol(Builder.withFoo, Decl(chainedThisRefinements.ts, 1, 30)) +>this : Symbol(Builder, Decl(chainedThisRefinements.ts, 0, 0)) +>withFoo : Symbol(Builder.withFoo, Decl(chainedThisRefinements.ts, 1, 30)) +>T : Symbol(T, Decl(chainedThisRefinements.ts, 8, 15)) +>withBar : Symbol(Builder.withBar, Decl(chainedThisRefinements.ts, 4, 5)) +>T : Symbol(T, Decl(chainedThisRefinements.ts, 8, 15)) +>bar : Symbol(bar, Decl(chainedThisRefinements.ts, 6, 31)) + return this.withFoo().withBar(); >this.withFoo().withBar : Symbol(Builder.withBar, Decl(chainedThisRefinements.ts, 4, 5)) >this.withFoo : Symbol(Builder.withFoo, Decl(chainedThisRefinements.ts, 1, 30)) @@ -39,11 +61,51 @@ class Builder { } declare var f: {foo: number}; ->f : Symbol(f, Decl(chainedThisRefinements.ts, 13, 11)) ->foo : Symbol(foo, Decl(chainedThisRefinements.ts, 13, 16)) +>f : Symbol(f, Decl(chainedThisRefinements.ts, 15, 11)) +>foo : Symbol(foo, Decl(chainedThisRefinements.ts, 15, 16)) + +new Builder().withFoo().withBar().foo; +>new Builder().withFoo().withBar().foo : Symbol(foo, Decl(chainedThisRefinements.ts, 3, 31)) +>new Builder().withFoo().withBar : Symbol(Builder.withBar, Decl(chainedThisRefinements.ts, 4, 5)) +>new Builder().withFoo : Symbol(Builder.withFoo, Decl(chainedThisRefinements.ts, 1, 30)) +>Builder : Symbol(Builder, Decl(chainedThisRefinements.ts, 0, 0)) +>withFoo : Symbol(Builder.withFoo, Decl(chainedThisRefinements.ts, 1, 30)) +>withBar : Symbol(Builder.withBar, Decl(chainedThisRefinements.ts, 4, 5)) +>foo : Symbol(foo, Decl(chainedThisRefinements.ts, 3, 31)) + +new Builder().withFoo().withBar().bar; +>new Builder().withFoo().withBar().bar : Symbol(bar, Decl(chainedThisRefinements.ts, 6, 31)) +>new Builder().withFoo().withBar : Symbol(Builder.withBar, Decl(chainedThisRefinements.ts, 4, 5)) +>new Builder().withFoo : Symbol(Builder.withFoo, Decl(chainedThisRefinements.ts, 1, 30)) +>Builder : Symbol(Builder, Decl(chainedThisRefinements.ts, 0, 0)) +>withFoo : Symbol(Builder.withFoo, Decl(chainedThisRefinements.ts, 1, 30)) +>withBar : Symbol(Builder.withBar, Decl(chainedThisRefinements.ts, 4, 5)) +>bar : Symbol(bar, Decl(chainedThisRefinements.ts, 6, 31)) + +f = new Builder().withFoo().withBar(); +>f : Symbol(f, Decl(chainedThisRefinements.ts, 15, 11)) +>new Builder().withFoo().withBar : Symbol(Builder.withBar, Decl(chainedThisRefinements.ts, 4, 5)) +>new Builder().withFoo : Symbol(Builder.withFoo, Decl(chainedThisRefinements.ts, 1, 30)) +>Builder : Symbol(Builder, Decl(chainedThisRefinements.ts, 0, 0)) +>withFoo : Symbol(Builder.withFoo, Decl(chainedThisRefinements.ts, 1, 30)) +>withBar : Symbol(Builder.withBar, Decl(chainedThisRefinements.ts, 4, 5)) + +new Builder().withFooBar().foo; +>new Builder().withFooBar().foo : Symbol(foo, Decl(chainedThisRefinements.ts, 3, 31)) +>new Builder().withFooBar : Symbol(Builder.withFooBar, Decl(chainedThisRefinements.ts, 7, 5)) +>Builder : Symbol(Builder, Decl(chainedThisRefinements.ts, 0, 0)) +>withFooBar : Symbol(Builder.withFooBar, Decl(chainedThisRefinements.ts, 7, 5)) +>foo : Symbol(foo, Decl(chainedThisRefinements.ts, 3, 31)) + +new Builder().withFooBar().bar; +>new Builder().withFooBar().bar : Symbol(bar, Decl(chainedThisRefinements.ts, 6, 31)) +>new Builder().withFooBar : Symbol(Builder.withFooBar, Decl(chainedThisRefinements.ts, 7, 5)) +>Builder : Symbol(Builder, Decl(chainedThisRefinements.ts, 0, 0)) +>withFooBar : Symbol(Builder.withFooBar, Decl(chainedThisRefinements.ts, 7, 5)) +>bar : Symbol(bar, Decl(chainedThisRefinements.ts, 6, 31)) -f = new Builder().withFooBar(); // should work ->f : Symbol(f, Decl(chainedThisRefinements.ts, 13, 11)) +f = new Builder().withFooBar(); +>f : Symbol(f, Decl(chainedThisRefinements.ts, 15, 11)) >new Builder().withFooBar : Symbol(Builder.withFooBar, Decl(chainedThisRefinements.ts, 7, 5)) >Builder : Symbol(Builder, Decl(chainedThisRefinements.ts, 0, 0)) >withFooBar : Symbol(Builder.withFooBar, Decl(chainedThisRefinements.ts, 7, 5)) diff --git a/tests/baselines/reference/chainedThisRefinements.types b/tests/baselines/reference/chainedThisRefinements.types index 6d6cfac9dd2c7..6b03ee427d365 100644 --- a/tests/baselines/reference/chainedThisRefinements.types +++ b/tests/baselines/reference/chainedThisRefinements.types @@ -22,16 +22,38 @@ class Builder { >bar : T } withFooBar() { ->withFooBar : () => this & { foo: T; } & { bar: T; } +>withFooBar : () => Builder & { foo: T; } & { bar: T; } + + this.withFoo().withBar().foo; +>this.withFoo().withBar().foo : T +>this.withFoo().withBar() : Builder & { foo: T; } & { bar: T; } +>this.withFoo().withBar : () => Builder & { foo: T; } & { bar: T; } +>this.withFoo() : this & { foo: T; } +>this.withFoo : () => this & { foo: T; } +>this : this +>withFoo : () => this & { foo: T; } +>withBar : () => Builder & { foo: T; } & { bar: T; } +>foo : T + + this.withFoo().withBar().bar; +>this.withFoo().withBar().bar : T +>this.withFoo().withBar() : Builder & { foo: T; } & { bar: T; } +>this.withFoo().withBar : () => Builder & { foo: T; } & { bar: T; } +>this.withFoo() : this & { foo: T; } +>this.withFoo : () => this & { foo: T; } +>this : this +>withFoo : () => this & { foo: T; } +>withBar : () => Builder & { foo: T; } & { bar: T; } +>bar : T return this.withFoo().withBar(); ->this.withFoo().withBar() : this & { foo: T; } & { bar: T; } ->this.withFoo().withBar : () => this & { foo: T; } & { bar: T; } +>this.withFoo().withBar() : Builder & { foo: T; } & { bar: T; } +>this.withFoo().withBar : () => Builder & { foo: T; } & { bar: T; } >this.withFoo() : this & { foo: T; } >this.withFoo : () => this & { foo: T; } >this : this >withFoo : () => this & { foo: T; } ->withBar : () => this & { foo: T; } & { bar: T; } +>withBar : () => Builder & { foo: T; } & { bar: T; } } } @@ -39,7 +61,61 @@ declare var f: {foo: number}; >f : { foo: number; } >foo : number -f = new Builder().withFooBar(); // should work +new Builder().withFoo().withBar().foo; +>new Builder().withFoo().withBar().foo : number +>new Builder().withFoo().withBar() : Builder & { foo: number; } & { bar: number; } +>new Builder().withFoo().withBar : () => Builder & { foo: number; } & { bar: T; } +>new Builder().withFoo() : Builder & { foo: number; } +>new Builder().withFoo : () => Builder & { foo: T; } +>new Builder() : Builder +>Builder : typeof Builder +>withFoo : () => Builder & { foo: T; } +>withBar : () => Builder & { foo: number; } & { bar: T; } +>foo : number + +new Builder().withFoo().withBar().bar; +>new Builder().withFoo().withBar().bar : number +>new Builder().withFoo().withBar() : Builder & { foo: number; } & { bar: number; } +>new Builder().withFoo().withBar : () => Builder & { foo: number; } & { bar: T; } +>new Builder().withFoo() : Builder & { foo: number; } +>new Builder().withFoo : () => Builder & { foo: T; } +>new Builder() : Builder +>Builder : typeof Builder +>withFoo : () => Builder & { foo: T; } +>withBar : () => Builder & { foo: number; } & { bar: T; } +>bar : number + +f = new Builder().withFoo().withBar(); +>f = new Builder().withFoo().withBar() : Builder & { foo: number; } & { bar: number; } +>f : { foo: number; } +>new Builder().withFoo().withBar() : Builder & { foo: number; } & { bar: number; } +>new Builder().withFoo().withBar : () => Builder & { foo: number; } & { bar: T; } +>new Builder().withFoo() : Builder & { foo: number; } +>new Builder().withFoo : () => Builder & { foo: T; } +>new Builder() : Builder +>Builder : typeof Builder +>withFoo : () => Builder & { foo: T; } +>withBar : () => Builder & { foo: number; } & { bar: T; } + +new Builder().withFooBar().foo; +>new Builder().withFooBar().foo : number +>new Builder().withFooBar() : Builder & { foo: number; } & { bar: number; } +>new Builder().withFooBar : () => Builder & { foo: T; } & { bar: T; } +>new Builder() : Builder +>Builder : typeof Builder +>withFooBar : () => Builder & { foo: T; } & { bar: T; } +>foo : number + +new Builder().withFooBar().bar; +>new Builder().withFooBar().bar : number +>new Builder().withFooBar() : Builder & { foo: number; } & { bar: number; } +>new Builder().withFooBar : () => Builder & { foo: T; } & { bar: T; } +>new Builder() : Builder +>Builder : typeof Builder +>withFooBar : () => Builder & { foo: T; } & { bar: T; } +>bar : number + +f = new Builder().withFooBar(); >f = new Builder().withFooBar() : Builder & { foo: number; } & { bar: number; } >f : { foo: number; } >new Builder().withFooBar() : Builder & { foo: number; } & { bar: number; } diff --git a/tests/baselines/reference/privateClassPropertyAccessibleWithinClass.types b/tests/baselines/reference/privateClassPropertyAccessibleWithinClass.types index 5286db36a8f1f..56aedbe253545 100644 --- a/tests/baselines/reference/privateClassPropertyAccessibleWithinClass.types +++ b/tests/baselines/reference/privateClassPropertyAccessibleWithinClass.types @@ -51,7 +51,7 @@ class C { >x : string private static foo() { return this.foo; } ->foo : () => () => typeof C.foo +>foo : () => typeof C.foo >this.foo : () => typeof C.foo >this : typeof C >foo : () => typeof C.foo diff --git a/tests/baselines/reference/privateClassPropertyAccessibleWithinNestedClass.types b/tests/baselines/reference/privateClassPropertyAccessibleWithinNestedClass.types index 9a6b1130748b8..c5338b68c41e5 100644 --- a/tests/baselines/reference/privateClassPropertyAccessibleWithinNestedClass.types +++ b/tests/baselines/reference/privateClassPropertyAccessibleWithinNestedClass.types @@ -51,7 +51,7 @@ class C { >x : string private static foo() { return this.foo; } ->foo : () => () => typeof C.foo +>foo : () => typeof C.foo >this.foo : () => typeof C.foo >this : typeof C >foo : () => typeof C.foo diff --git a/tests/baselines/reference/protectedClassPropertyAccessibleWithinClass.types b/tests/baselines/reference/protectedClassPropertyAccessibleWithinClass.types index 5130416b98528..1e325d1d6f5e1 100644 --- a/tests/baselines/reference/protectedClassPropertyAccessibleWithinClass.types +++ b/tests/baselines/reference/protectedClassPropertyAccessibleWithinClass.types @@ -51,7 +51,7 @@ class C { >x : string protected static foo() { return this.foo; } ->foo : () => () => typeof C.foo +>foo : () => typeof C.foo >this.foo : () => typeof C.foo >this : typeof C >foo : () => typeof C.foo diff --git a/tests/baselines/reference/protectedClassPropertyAccessibleWithinNestedClass.types b/tests/baselines/reference/protectedClassPropertyAccessibleWithinNestedClass.types index 39987a615e76f..6b6bf6edfc9fb 100644 --- a/tests/baselines/reference/protectedClassPropertyAccessibleWithinNestedClass.types +++ b/tests/baselines/reference/protectedClassPropertyAccessibleWithinNestedClass.types @@ -51,7 +51,7 @@ class C { >x : string protected static foo() { return this.foo; } ->foo : () => () => typeof C.foo +>foo : () => typeof C.foo >this.foo : () => typeof C.foo >this : typeof C >foo : () => typeof C.foo diff --git a/tests/baselines/reference/recursiveFunctionTypes.types b/tests/baselines/reference/recursiveFunctionTypes.types index d3f2f84574d68..72ba77b48f6f9 100644 --- a/tests/baselines/reference/recursiveFunctionTypes.types +++ b/tests/baselines/reference/recursiveFunctionTypes.types @@ -47,7 +47,7 @@ class C { >C : C static g(t: typeof C.g){ } ->g : (t: (t: typeof C.g) => void) => void +>g : (t: typeof C.g) => void >t : (t: typeof C.g) => void >C.g : (t: typeof C.g) => void >C : typeof C diff --git a/tests/baselines/reference/recursiveFunctionTypes1.types b/tests/baselines/reference/recursiveFunctionTypes1.types index 9026196682e4c..52cf90f1059d4 100644 --- a/tests/baselines/reference/recursiveFunctionTypes1.types +++ b/tests/baselines/reference/recursiveFunctionTypes1.types @@ -3,7 +3,7 @@ class C { >C : C static g(t: typeof C.g){ } ->g : (t: (t: typeof C.g) => void) => void +>g : (t: typeof C.g) => void >t : (t: typeof C.g) => void >C.g : (t: typeof C.g) => void >C : typeof C diff --git a/tests/baselines/reference/thisTypeInFunctionsNegative.errors.txt b/tests/baselines/reference/thisTypeInFunctionsNegative.errors.txt index 428ea42e6d056..9222b23d4f1dd 100644 --- a/tests/baselines/reference/thisTypeInFunctionsNegative.errors.txt +++ b/tests/baselines/reference/thisTypeInFunctionsNegative.errors.txt @@ -69,8 +69,6 @@ tests/cases/conformance/types/thisType/thisTypeInFunctionsNegative.ts(146,1): er The 'this' types of each signature are incompatible. Type 'Base1' is not assignable to type 'Base2'. tests/cases/conformance/types/thisType/thisTypeInFunctionsNegative.ts(148,1): error TS2322: Type '(this: Base2) => number' is not assignable to type '(this: Base1) => number'. - The 'this' types of each signature are incompatible. - Type 'Base1' is not assignable to type 'Base2'. tests/cases/conformance/types/thisType/thisTypeInFunctionsNegative.ts(154,16): error TS2679: A function that is called with the 'new' keyword cannot have a 'this' type that is 'void'. tests/cases/conformance/types/thisType/thisTypeInFunctionsNegative.ts(158,17): error TS2681: A constructor cannot have a 'this' parameter. tests/cases/conformance/types/thisType/thisTypeInFunctionsNegative.ts(162,9): error TS2681: A constructor cannot have a 'this' parameter. @@ -366,8 +364,6 @@ tests/cases/conformance/types/thisType/thisTypeInFunctionsNegative.ts(178,22): e d1.explicit = b2.polymorphic // error, 'y' not in Base1: { x } ~~~~~~~~~~~ !!! error TS2322: Type '(this: Base2) => number' is not assignable to type '(this: Base1) => number'. -!!! error TS2322: The 'this' types of each signature are incompatible. -!!! error TS2322: Type 'Base1' is not assignable to type 'Base2'. ////// use this-type for construction with new //// function VoidThis(this: void) { diff --git a/tests/cases/compiler/chainedThisRefinements.ts b/tests/cases/compiler/chainedThisRefinements.ts index 78eb1db232452..7dab042d628d2 100644 --- a/tests/cases/compiler/chainedThisRefinements.ts +++ b/tests/cases/compiler/chainedThisRefinements.ts @@ -7,9 +7,16 @@ class Builder { return this as this & { bar: T } } withFooBar() { + this.withFoo().withBar().foo; + this.withFoo().withBar().bar; return this.withFoo().withBar(); } } declare var f: {foo: number}; -f = new Builder().withFooBar(); // should work +new Builder().withFoo().withBar().foo; +new Builder().withFoo().withBar().bar; +f = new Builder().withFoo().withBar(); +new Builder().withFooBar().foo; +new Builder().withFooBar().bar; +f = new Builder().withFooBar();