Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
8 changes: 4 additions & 4 deletions src/compiler/binder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2859,10 +2859,10 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void {
break;
}
// falls through
case SyntaxKind.ThisKeyword:
if (node.kind === SyntaxKind.ThisKeyword) {
seenThisKeyword = true;
}
case SyntaxKind.ThisKeyword:
if (node.kind === SyntaxKind.ThisKeyword || (node.kind === SyntaxKind.Identifier && (node as Identifier).escapedText === "this" && isPartOfTypeQuery(node))) {
seenThisKeyword = true;
}
// TODO: Why use `isExpression` here? both Identifier and ThisKeyword are expressions.
if (currentFlow && (isExpression(node) || parent.kind === SyntaxKind.ShorthandPropertyAssignment)) {
(node as Identifier | ThisExpression).flowNode = currentFlow;
Expand Down
113 changes: 113 additions & 0 deletions tests/baselines/reference/typeofThisWithContextualThisParameter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
//// [tests/cases/compiler/typeofThisWithContextualThisParameter.ts] ////

//// [typeofThisWithContextualThisParameter.ts]
// Reproduces #63616: typeof this inconsistent when this parameter comes from a contextual signature

interface A { a: string }

// ---- Object-literal method case ----

{
interface B { g: (this: A) => void }

function f(_: B): void {}

// Case 1: typeof this without explicit this usage — should resolve to A
f({
g() {
type X = typeof this;
// ^ should be A
}
})

// Case 2: this used before typeof this — should resolve to A
f({
g() {
this;
type X = typeof this;
// ^ should be A
}
})

// Case 3: this used after typeof this — should resolve to A
f({
g() {
type X = typeof this;
// ^ should be A
this;
}
})
}

// ---- Function expression case ----

{
function f(_: (this: A) => void): void {}

// Case 4: typeof this only — should resolve to A (not implicit any error for typeof this context)
f(function g() {
type X = typeof this;
})

// Case 5: this used before typeof this — should resolve to A
f(function g() {
this;
type X = typeof this;
})

// Case 6: this used after typeof this — should resolve to A
f(function g() {
type X = typeof this;
this;
})
}


//// [typeofThisWithContextualThisParameter.js]
"use strict";
// Reproduces #63616: typeof this inconsistent when this parameter comes from a contextual signature
// ---- Object-literal method case ----
{
function f(_) { }
// Case 1: typeof this without explicit this usage — should resolve to A
f({
g() {
// ^ should be A
}
});
// Case 2: this used before typeof this — should resolve to A
f({
g() {
this;
// ^ should be A
}
});
// Case 3: this used after typeof this — should resolve to A
f({
g() {
// ^ should be A
this;
}
});
}
// ---- Function expression case ----
{
function f(_) { }
// Case 4: typeof this only — should resolve to A (not implicit any error for typeof this context)
f(function g() {
});
// Case 5: this used before typeof this — should resolve to A
f(function g() {
this;
});
// Case 6: this used after typeof this — should resolve to A
f(function g() {
this;
});
}


//// [typeofThisWithContextualThisParameter.d.ts]
interface A {
a: string;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
//// [tests/cases/compiler/typeofThisWithContextualThisParameter.ts] ////

=== typeofThisWithContextualThisParameter.ts ===
// Reproduces #63616: typeof this inconsistent when this parameter comes from a contextual signature

interface A { a: string }
>A : Symbol(A, Decl(typeofThisWithContextualThisParameter.ts, 0, 0))
>a : Symbol(A.a, Decl(typeofThisWithContextualThisParameter.ts, 2, 13))

// ---- Object-literal method case ----

{
interface B { g: (this: A) => void }
>B : Symbol(B, Decl(typeofThisWithContextualThisParameter.ts, 6, 1))
>g : Symbol(B.g, Decl(typeofThisWithContextualThisParameter.ts, 7, 17))
>this : Symbol(this, Decl(typeofThisWithContextualThisParameter.ts, 7, 22))
>A : Symbol(A, Decl(typeofThisWithContextualThisParameter.ts, 0, 0))

function f(_: B): void {}
>f : Symbol(f, Decl(typeofThisWithContextualThisParameter.ts, 7, 40))
>_ : Symbol(_, Decl(typeofThisWithContextualThisParameter.ts, 9, 15))
>B : Symbol(B, Decl(typeofThisWithContextualThisParameter.ts, 6, 1))

// Case 1: typeof this without explicit this usage — should resolve to A
f({
>f : Symbol(f, Decl(typeofThisWithContextualThisParameter.ts, 7, 40))

g() {
>g : Symbol(g, Decl(typeofThisWithContextualThisParameter.ts, 12, 7))

type X = typeof this;
>X : Symbol(X, Decl(typeofThisWithContextualThisParameter.ts, 13, 13))
>this : Symbol(this, Decl(typeofThisWithContextualThisParameter.ts, 7, 22))

// ^ should be A
}
})

// Case 2: this used before typeof this — should resolve to A
f({
>f : Symbol(f, Decl(typeofThisWithContextualThisParameter.ts, 7, 40))

g() {
>g : Symbol(g, Decl(typeofThisWithContextualThisParameter.ts, 20, 7))

this;
>this : Symbol(this, Decl(typeofThisWithContextualThisParameter.ts, 7, 22))

type X = typeof this;
>X : Symbol(X, Decl(typeofThisWithContextualThisParameter.ts, 22, 17))
>this : Symbol(this, Decl(typeofThisWithContextualThisParameter.ts, 7, 22))

// ^ should be A
}
})

// Case 3: this used after typeof this — should resolve to A
f({
>f : Symbol(f, Decl(typeofThisWithContextualThisParameter.ts, 7, 40))

g() {
>g : Symbol(g, Decl(typeofThisWithContextualThisParameter.ts, 29, 7))

type X = typeof this;
>X : Symbol(X, Decl(typeofThisWithContextualThisParameter.ts, 30, 13))
>this : Symbol(this, Decl(typeofThisWithContextualThisParameter.ts, 7, 22))

// ^ should be A
this;
>this : Symbol(this, Decl(typeofThisWithContextualThisParameter.ts, 7, 22))
}
})
}

// ---- Function expression case ----

{
function f(_: (this: A) => void): void {}
>f : Symbol(f, Decl(typeofThisWithContextualThisParameter.ts, 40, 1))
>_ : Symbol(_, Decl(typeofThisWithContextualThisParameter.ts, 41, 15))
>this : Symbol(this, Decl(typeofThisWithContextualThisParameter.ts, 41, 19))
>A : Symbol(A, Decl(typeofThisWithContextualThisParameter.ts, 0, 0))

// Case 4: typeof this only — should resolve to A (not implicit any error for typeof this context)
f(function g() {
>f : Symbol(f, Decl(typeofThisWithContextualThisParameter.ts, 40, 1))
>g : Symbol(g, Decl(typeofThisWithContextualThisParameter.ts, 44, 6))

type X = typeof this;
>X : Symbol(X, Decl(typeofThisWithContextualThisParameter.ts, 44, 20))
>this : Symbol(this, Decl(typeofThisWithContextualThisParameter.ts, 41, 19))

})

// Case 5: this used before typeof this — should resolve to A
f(function g() {
>f : Symbol(f, Decl(typeofThisWithContextualThisParameter.ts, 40, 1))
>g : Symbol(g, Decl(typeofThisWithContextualThisParameter.ts, 49, 6))

this;
>this : Symbol(this, Decl(typeofThisWithContextualThisParameter.ts, 41, 19))

type X = typeof this;
>X : Symbol(X, Decl(typeofThisWithContextualThisParameter.ts, 50, 13))
>this : Symbol(this, Decl(typeofThisWithContextualThisParameter.ts, 41, 19))

})

// Case 6: this used after typeof this — should resolve to A
f(function g() {
>f : Symbol(f, Decl(typeofThisWithContextualThisParameter.ts, 40, 1))
>g : Symbol(g, Decl(typeofThisWithContextualThisParameter.ts, 55, 6))

type X = typeof this;
>X : Symbol(X, Decl(typeofThisWithContextualThisParameter.ts, 55, 20))
>this : Symbol(this, Decl(typeofThisWithContextualThisParameter.ts, 41, 19))

this;
>this : Symbol(this, Decl(typeofThisWithContextualThisParameter.ts, 41, 19))

})
}

Loading