-
Notifications
You must be signed in to change notification settings - Fork 12.8k
Instantiate this
in non-super property/element access expressions
#29468
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6631,6 +6631,9 @@ namespace ts { | |
else if (type.flags & TypeFlags.Intersection) { | ||
return getIntersectionType(map((<IntersectionType>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 { | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. extra newline is extra |
||
if (type.target === globalThisType && type.typeArguments && type.typeArguments[0].flags & TypeFlags.TypeParameter && | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I also don't understand what There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's the |
||
(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 ? | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
//// [chainedThisRefinements.ts] | ||
class Builder { | ||
private _class: undefined; | ||
withFoo<T>() { | ||
return this as this & { foo: T } | ||
} | ||
withBar<T>() { | ||
return this as this & { bar: T } | ||
} | ||
withFooBar<T>() { | ||
this.withFoo<T>().withBar<T>().foo; | ||
this.withFoo<T>().withBar<T>().bar; | ||
return this.withFoo<T>().withBar<T>(); | ||
} | ||
} | ||
|
||
declare var f: {foo: number}; | ||
new Builder().withFoo<number>().withBar<number>().foo; | ||
new Builder().withFoo<number>().withBar<number>().bar; | ||
f = new Builder().withFoo<number>().withBar<number>(); | ||
new Builder().withFooBar<number>().foo; | ||
new Builder().withFooBar<number>().bar; | ||
f = new Builder().withFooBar<number>(); | ||
|
||
|
||
//// [chainedThisRefinements.js] | ||
var Builder = /** @class */ (function () { | ||
function Builder() { | ||
} | ||
Builder.prototype.withFoo = function () { | ||
return this; | ||
}; | ||
Builder.prototype.withBar = function () { | ||
return this; | ||
}; | ||
Builder.prototype.withFooBar = function () { | ||
this.withFoo().withBar().foo; | ||
this.withFoo().withBar().bar; | ||
return this.withFoo().withBar(); | ||
}; | ||
return Builder; | ||
}()); | ||
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(); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
=== 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<T>() { | ||
>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<T>() { | ||
>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<T>() { | ||
>withFooBar : Symbol(Builder.withFooBar, Decl(chainedThisRefinements.ts, 7, 5)) | ||
>T : Symbol(T, Decl(chainedThisRefinements.ts, 8, 15)) | ||
|
||
this.withFoo<T>().withBar<T>().foo; | ||
>this.withFoo<T>().withBar<T>().foo : Symbol(foo, Decl(chainedThisRefinements.ts, 3, 31)) | ||
>this.withFoo<T>().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<T>().withBar<T>().bar; | ||
>this.withFoo<T>().withBar<T>().bar : Symbol(bar, Decl(chainedThisRefinements.ts, 6, 31)) | ||
>this.withFoo<T>().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<T>().withBar<T>(); | ||
>this.withFoo<T>().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, 15, 11)) | ||
>foo : Symbol(foo, Decl(chainedThisRefinements.ts, 15, 16)) | ||
|
||
new Builder().withFoo<number>().withBar<number>().foo; | ||
>new Builder().withFoo<number>().withBar<number>().foo : Symbol(foo, Decl(chainedThisRefinements.ts, 3, 31)) | ||
>new Builder().withFoo<number>().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<number>().withBar<number>().bar; | ||
>new Builder().withFoo<number>().withBar<number>().bar : Symbol(bar, Decl(chainedThisRefinements.ts, 6, 31)) | ||
>new Builder().withFoo<number>().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<number>().withBar<number>(); | ||
>f : Symbol(f, Decl(chainedThisRefinements.ts, 15, 11)) | ||
>new Builder().withFoo<number>().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<number>().foo; | ||
>new Builder().withFooBar<number>().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<number>().bar; | ||
>new Builder().withFooBar<number>().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<number>(); | ||
>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)) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
=== tests/cases/compiler/chainedThisRefinements.ts === | ||
class Builder { | ||
>Builder : Builder | ||
|
||
private _class: undefined; | ||
>_class : undefined | ||
|
||
withFoo<T>() { | ||
>withFoo : <T>() => this & { foo: T; } | ||
|
||
return this as this & { foo: T } | ||
>this as this & { foo: T } : this & { foo: T; } | ||
>this : this | ||
>foo : T | ||
} | ||
withBar<T>() { | ||
>withBar : <T>() => this & { bar: T; } | ||
|
||
return this as this & { bar: T } | ||
>this as this & { bar: T } : this & { bar: T; } | ||
>this : this | ||
>bar : T | ||
} | ||
withFooBar<T>() { | ||
>withFooBar : <T>() => Builder & { foo: T; } & { bar: T; } | ||
|
||
this.withFoo<T>().withBar<T>().foo; | ||
>this.withFoo<T>().withBar<T>().foo : T | ||
>this.withFoo<T>().withBar<T>() : Builder & { foo: T; } & { bar: T; } | ||
>this.withFoo<T>().withBar : <T>() => Builder & { foo: T; } & { bar: T; } | ||
>this.withFoo<T>() : this & { foo: T; } | ||
>this.withFoo : <T>() => this & { foo: T; } | ||
>this : this | ||
>withFoo : <T>() => this & { foo: T; } | ||
>withBar : <T>() => Builder & { foo: T; } & { bar: T; } | ||
>foo : T | ||
|
||
this.withFoo<T>().withBar<T>().bar; | ||
>this.withFoo<T>().withBar<T>().bar : T | ||
>this.withFoo<T>().withBar<T>() : Builder & { foo: T; } & { bar: T; } | ||
>this.withFoo<T>().withBar : <T>() => Builder & { foo: T; } & { bar: T; } | ||
>this.withFoo<T>() : this & { foo: T; } | ||
>this.withFoo : <T>() => this & { foo: T; } | ||
>this : this | ||
>withFoo : <T>() => this & { foo: T; } | ||
>withBar : <T>() => Builder & { foo: T; } & { bar: T; } | ||
>bar : T | ||
|
||
return this.withFoo<T>().withBar<T>(); | ||
>this.withFoo<T>().withBar<T>() : Builder & { foo: T; } & { bar: T; } | ||
>this.withFoo<T>().withBar : <T>() => Builder & { foo: T; } & { bar: T; } | ||
>this.withFoo<T>() : this & { foo: T; } | ||
>this.withFoo : <T>() => this & { foo: T; } | ||
>this : this | ||
>withFoo : <T>() => this & { foo: T; } | ||
>withBar : <T>() => Builder & { foo: T; } & { bar: T; } | ||
} | ||
} | ||
|
||
declare var f: {foo: number}; | ||
>f : { foo: number; } | ||
>foo : number | ||
|
||
new Builder().withFoo<number>().withBar<number>().foo; | ||
>new Builder().withFoo<number>().withBar<number>().foo : number | ||
>new Builder().withFoo<number>().withBar<number>() : Builder & { foo: number; } & { bar: number; } | ||
>new Builder().withFoo<number>().withBar : <T>() => Builder & { foo: number; } & { bar: T; } | ||
>new Builder().withFoo<number>() : Builder & { foo: number; } | ||
>new Builder().withFoo : <T>() => Builder & { foo: T; } | ||
>new Builder() : Builder | ||
>Builder : typeof Builder | ||
>withFoo : <T>() => Builder & { foo: T; } | ||
>withBar : <T>() => Builder & { foo: number; } & { bar: T; } | ||
>foo : number | ||
|
||
new Builder().withFoo<number>().withBar<number>().bar; | ||
>new Builder().withFoo<number>().withBar<number>().bar : number | ||
>new Builder().withFoo<number>().withBar<number>() : Builder & { foo: number; } & { bar: number; } | ||
>new Builder().withFoo<number>().withBar : <T>() => Builder & { foo: number; } & { bar: T; } | ||
>new Builder().withFoo<number>() : Builder & { foo: number; } | ||
>new Builder().withFoo : <T>() => Builder & { foo: T; } | ||
>new Builder() : Builder | ||
>Builder : typeof Builder | ||
>withFoo : <T>() => Builder & { foo: T; } | ||
>withBar : <T>() => Builder & { foo: number; } & { bar: T; } | ||
>bar : number | ||
|
||
f = new Builder().withFoo<number>().withBar<number>(); | ||
>f = new Builder().withFoo<number>().withBar<number>() : Builder & { foo: number; } & { bar: number; } | ||
>f : { foo: number; } | ||
>new Builder().withFoo<number>().withBar<number>() : Builder & { foo: number; } & { bar: number; } | ||
>new Builder().withFoo<number>().withBar : <T>() => Builder & { foo: number; } & { bar: T; } | ||
>new Builder().withFoo<number>() : Builder & { foo: number; } | ||
>new Builder().withFoo : <T>() => Builder & { foo: T; } | ||
>new Builder() : Builder | ||
>Builder : typeof Builder | ||
>withFoo : <T>() => Builder & { foo: T; } | ||
>withBar : <T>() => Builder & { foo: number; } & { bar: T; } | ||
|
||
new Builder().withFooBar<number>().foo; | ||
>new Builder().withFooBar<number>().foo : number | ||
>new Builder().withFooBar<number>() : Builder & { foo: number; } & { bar: number; } | ||
>new Builder().withFooBar : <T>() => Builder & { foo: T; } & { bar: T; } | ||
>new Builder() : Builder | ||
>Builder : typeof Builder | ||
>withFooBar : <T>() => Builder & { foo: T; } & { bar: T; } | ||
>foo : number | ||
|
||
new Builder().withFooBar<number>().bar; | ||
>new Builder().withFooBar<number>().bar : number | ||
>new Builder().withFooBar<number>() : Builder & { foo: number; } & { bar: number; } | ||
>new Builder().withFooBar : <T>() => Builder & { foo: T; } & { bar: T; } | ||
>new Builder() : Builder | ||
>Builder : typeof Builder | ||
>withFooBar : <T>() => Builder & { foo: T; } & { bar: T; } | ||
>bar : number | ||
|
||
f = new Builder().withFooBar<number>(); | ||
>f = new Builder().withFooBar<number>() : Builder & { foo: number; } & { bar: number; } | ||
>f : { foo: number; } | ||
>new Builder().withFooBar<number>() : Builder & { foo: number; } & { bar: number; } | ||
>new Builder().withFooBar : <T>() => Builder & { foo: T; } & { bar: T; } | ||
>new Builder() : Builder | ||
>Builder : typeof Builder | ||
>withFooBar : <T>() => Builder & { foo: T; } & { bar: T; } | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
class Builder { | ||
private _class: undefined; | ||
withFoo<T>() { | ||
return this as this & { foo: T } | ||
} | ||
withBar<T>() { | ||
return this as this & { bar: T } | ||
} | ||
withFooBar<T>() { | ||
this.withFoo<T>().withBar<T>().foo; | ||
this.withFoo<T>().withBar<T>().bar; | ||
return this.withFoo<T>().withBar<T>(); | ||
} | ||
} | ||
|
||
declare var f: {foo: number}; | ||
new Builder().withFoo<number>().withBar<number>().foo; | ||
new Builder().withFoo<number>().withBar<number>().bar; | ||
f = new Builder().withFoo<number>().withBar<number>(); | ||
new Builder().withFooBar<number>().foo; | ||
new Builder().withFooBar<number>().bar; | ||
f = new Builder().withFooBar<number>(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
globalThisType
?