Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
fix(eslint-plugin): [no-use-before-define] correctly handle typeof ty…
…pe references (#2623)
  • Loading branch information
Drakota committed Oct 11, 2020
1 parent 03886d7 commit 8e44c78
Show file tree
Hide file tree
Showing 2 changed files with 127 additions and 1 deletion.
33 changes: 32 additions & 1 deletion packages/eslint-plugin/src/rules/no-use-before-define.ts
Expand Up @@ -92,6 +92,37 @@ function isOuterVariable(
);
}

/**
* Recursively checks whether or not a given reference has a type query declaration among it's parents
*/
function referenceContainsTypeQuery(node: TSESTree.Node): boolean {
switch (node.type) {
case AST_NODE_TYPES.TSTypeQuery:
return true;

case AST_NODE_TYPES.TSQualifiedName:
case AST_NODE_TYPES.Identifier:
if (!node.parent) {
return false;
}
return referenceContainsTypeQuery(node.parent);

default:
// if we find a different node, there's no chance that we're in a TSTypeQuery
return false;
}
}

/**
* Checks whether or not a given reference is a type reference.
*/
function isTypeReference(reference: TSESLint.Scope.Reference): boolean {
return (
reference.isTypeReference ||
referenceContainsTypeQuery(reference.identifier)
);
}

/**
* Checks whether or not a given location is inside of the range of a given node.
*/
Expand Down Expand Up @@ -219,7 +250,7 @@ export default util.createRule<Options, MessageIds>({
variable: TSESLint.Scope.Variable,
reference: TSESLint.Scope.Reference,
): boolean {
if (reference.isTypeReference && options.ignoreTypeReferences) {
if (options.ignoreTypeReferences && isTypeReference(reference)) {
return false;
}
if (isFunction(variable)) {
Expand Down
95 changes: 95 additions & 0 deletions packages/eslint-plugin/tests/rules/no-use-before-define.test.ts
Expand Up @@ -219,7 +219,43 @@ type Foo = string | number;
`,
options: [{ typedefs: false }],
},
// https://github.com/typescript-eslint/typescript-eslint/issues/2572
{
code: `
interface Bar {
type: typeof Foo;
}
const Foo = 2;
`,
options: [{ ignoreTypeReferences: true }],
},
{
code: `
interface Bar {
type: typeof Foo.FOO;
}
class Foo {
public static readonly FOO = '';
}
`,
options: [{ ignoreTypeReferences: true }],
},
{
code: `
interface Bar {
type: typeof Foo.Bar.Baz;
}
const Foo = {
Bar: {
Baz: 1,
},
};
`,
options: [{ ignoreTypeReferences: true }],
},
// https://github.com/bradzacher/eslint-plugin-typescript/issues/141
{
code: `
Expand Down Expand Up @@ -875,6 +911,65 @@ for (var a of a) {
],
},

// "ignoreTypeReferences" option
{
code: `
interface Bar {
type: typeof Foo;
}
const Foo = 2;
`,
options: [{ ignoreTypeReferences: false }],
errors: [
{
messageId: 'noUseBeforeDefine',
data: { name: 'Foo' },
type: AST_NODE_TYPES.Identifier,
},
],
},
{
code: `
interface Bar {
type: typeof Foo.FOO;
}
class Foo {
public static readonly FOO = '';
}
`,
options: [{ ignoreTypeReferences: false }],
errors: [
{
messageId: 'noUseBeforeDefine',
data: { name: 'Foo' },
type: AST_NODE_TYPES.Identifier,
},
],
},
{
code: `
interface Bar {
type: typeof Foo.Bar.Baz;
}
const Foo = {
Bar: {
Baz: 1,
},
};
`,
options: [{ ignoreTypeReferences: false }],
errors: [
{
messageId: 'noUseBeforeDefine',
data: { name: 'Foo' },
type: AST_NODE_TYPES.Identifier,
},
],
},

// "variables" option
{
code: `
Expand Down

0 comments on commit 8e44c78

Please sign in to comment.