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
feat: treat this
in typeof this
as a ThisExpression
#4382
Changes from 10 commits
3caf3c5
ae25168
1a6ef43
1680e54
92da63c
fdbc897
c924ee3
3aa666e
204c0bb
3d09e4d
b03c226
b699f0c
fcbaa5d
751fd94
df847c1
a60ceee
b9f12b9
d42ecff
042c6f2
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 |
---|---|---|
@@ -1,4 +1,5 @@ | ||
import type { Identifier } from '../expression/Identifier/spec'; | ||
import type { ThisExpression } from '../expression/ThisExpression/spec'; | ||
import type { TSQualifiedName } from '../type/TSQualifiedName/spec'; | ||
|
||
export type EntityName = Identifier | TSQualifiedName; | ||
export type EntityName = Identifier | ThisExpression | TSQualifiedName; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
let self: typeof this; | ||
let foo: typeof this.foo; |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -662,3 +662,29 @@ export function firstDefined<T, U>( | |
} | ||
return undefined; | ||
} | ||
|
||
export function identifierIsThisKeyword(id: ts.Identifier): boolean { | ||
return id.originalKeywordKind === SyntaxKind.ThisKeyword; | ||
} | ||
|
||
export function isThisIdentifier( | ||
node: ts.Node | undefined, | ||
): node is ts.Identifier { | ||
return ( | ||
!!node && | ||
node.kind === SyntaxKind.Identifier && | ||
identifierIsThisKeyword(node as ts.Identifier) | ||
); | ||
} | ||
|
||
export function isThisInTypeQuery(node: ts.Node): boolean { | ||
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. ditto above - use a predicate return type |
||
if (!isThisIdentifier(node)) { | ||
return false; | ||
} | ||
|
||
while (ts.isQualifiedName(node.parent) && node.parent.left === node) { | ||
node = node.parent; | ||
} | ||
|
||
return node.parent.kind === SyntaxKind.TypeQuery; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,6 @@ | ||
// babel types are something we don't really care about | ||
/* eslint-disable @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/restrict-plus-operands */ | ||
import type { File, Program } from '@babel/types'; | ||
import type { File, Identifier, Program, TSTypeQuery } from '@babel/types'; | ||
import { AST_NODE_TYPES, TSESTree } from '../../src/ts-estree'; | ||
import { deeplyCopy, omitDeep } from '../../tools/test-utils'; | ||
|
||
|
@@ -295,6 +295,27 @@ export function preprocessBabylonAST(ast: File): any { | |
delete node.loc.start.index; | ||
} | ||
}, | ||
TSTypeQuery(node: TSTypeQuery) { | ||
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. can you add an comment with explanation why we need this and if there is babel ticket please link it here, |
||
const { exprName } = node; | ||
const processIdentifier = (identifier: Identifier) => { | ||
if (identifier.name === 'this') { | ||
(identifier.type as string) = 'ThisExpression'; | ||
delete (identifier as { name?: string }).name; | ||
} | ||
}; | ||
if (exprName.type === 'Identifier') { | ||
processIdentifier(exprName); | ||
} else if (exprName.type === 'TSQualifiedName') { | ||
let qualifiedName = exprName; | ||
while (true) { | ||
if (qualifiedName.left.type === 'Identifier') { | ||
processIdentifier(qualifiedName.left); | ||
return; | ||
} | ||
qualifiedName = qualifiedName.left; | ||
} | ||
} | ||
}, | ||
}, | ||
); | ||
} | ||
|
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.
Changing the AST feels hacky and is gonna break some plugins. The
no-undef
rule usesglobalScope.through
to check undefined variables. Creating a variable calledthis
for functions should prevent eslint from reporting this.https://github.com/eslint/eslint/blob/main/lib/rules/no-undef.js#L59L75
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.
this looks like an issue in typescript, we should either get
SyntaxKind.ThisType
orSyntaxKind.ThisKeyword
playground 4.3.5
playground 4.5.4
const b: this = this
- is correctly reported asThisType
older versions of typescript (<4.4) reported
typeof this
as errorCannot find name 'this'. (2304)
we should add test cases for parser and visitor