eslint: Bug: `no-use-before-define` in combo with `export` keywords.

Environment

Node version: v17.7.2 npm version: v8.5.2 Local ESLint version: v7.32.0 (Currently used) Global ESLint version: Not found Operating System: linux 5.10.0-9-amd64 (Debian 10 Live-USB)

What parser are you using?

@typescript-eslint/parser

What did you do?

Configuration
{
	"env": {
		"browser": true
		,"es2021": true
	}
	,"extends": [
		"standard"
	]
	,"parser": "@typescript-eslint/parser"
	,"parserOptions": {
		"ecmaVersion": "latest"
		,"sourceType": "module"
	}
	,"plugins": [
		"@typescript-eslint"
	]
	,"rules": {
		"no-tabs": 0
		,"indent": ["error" ,"tab",{
			"SwitchCase": 1
			,"flatTernaryExpressions": false
			,"offsetTernaryExpressions": true
		}]
		,"brace-style": ["error" ,"stroustrup" ,{
			"allowSingleLine": true
		}]
		,"camelcase": ["error" ,{
			"properties": "always"
			,"ignoreGlobals": true
			,"allow": [
				"^UNSAFE_"
			 ]
		}]
		,"comma-spacing": ["error" ,{
			"before": true
			,"after": false
		}]
		// Manually disable/enable blocks until this bug is fixed...
		,"comma-style": ["error" ,"first"]
		// ,"comma-style": ["error" ,"first", {
		// 	"exceptions": {
		// 		"VariableDeclaration": true
		// 	}
		// }]
		// /Manually disable/enable blocks until this bug is fixed...

		,"eol-last": ["error", "never"]
		,"one-var": ["error" ,"consecutive"]
		,"operator-linebreak": ["error" ,"before" ,{
				"overrides": {
					"=": "after"
				}
			}
		]
		,"space-before-blocks": ["error" ,"never"]
		,"space-before-function-paren": ["error" ,"never"]
	}
}
import { x }	from	'./y.mjs'
export {
	logger as default
	,SomeClass
	,x
}

class SomeClass{
	// code
}

const logger = new SomeClass()

What did you expect to happen?

No complaint from eslint.

What actually happened?

  • logger was used before it was defined. eslint(no-use-before-define)
  • SomeClass was used before it was defined. eslint(no-use-before-define)

See also demo.

Participation

  • I am willing to submit a pull request for this issue.

Additional comments

What is needed for eslint to allow exports at top of modules in combination with no-use-before-define? Because JavaScript processes those keywords before the actual code they represent in modules. The style works perfectly without errors in browsers, but eslint forces you to place the export part at end of the file. Yes i know i could use the export keywords on the same line as the definition of them, but it is better for overview to place them at start like shown in code above.

That’s why i propose an exports flag in no-use-before-define#options) to control the wanted behaviour.


I’ll currently use this work-around for my exports at top until this is fixed/added: 😞

/* eslint-disable no-use-before-define */
export {
	logger as default
	,SomeClass
	,x
}
/* eslint-enable no-use-before-define */

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Reactions: 1
  • Comments: 16 (10 by maintainers)

Commits related to this issue

Most upvoted comments

@TriMoon ljharb is referring to our policies about stylistic rules.

@ljharb this rule was originally purely stylistic. As of es6, it can also be used to prevent TDZ errors, and the documentation for this rule does mention TDZ as one of the rationales for using the rule. Since this rule can be used for different purposes, I’m supportive of an option to disable a stylistic-only exports check so that the rule can be configured to only warn about statically determinable TDZ errors.

I’m just wondering why you choose to default to false in f6d7920#diff-c6cfabe41e087014db02d66b884c50157300e6309034ba79d548c2b421468f8eR128 Because the behavior of the language allows it by definition by hoisting them to top of the code (I would prefer it to defaulting to true to better reflect es6+ standard parsing)

This rule is primarily stylistic, so by default any reference that appears before the declaration is disallowed. References to function declarations are also disallowed by default, although they are hoisted.

Hi @TriMoon, thanks for the issue!

I can reproduce this, but it isn’t a bug. This rule is mostly stylistic, so it reports references that appear before declarations even when those references do not cause runtime errors.

That’s why i propose an exports flag in no-use-before-define#options) to control the wanted behaviour.

An option to always allow references inside export { ... } makes sense to me 👍