@typescript-eslint/no-use-before-define

Disallow using a variable, function, class, enum, or type above the line that declares it

Also called typescript-eslint/no-use-before-define, typescript/no-use-before-define

Reading a let, const, or class before its declaration runs throws a ReferenceError. Reading a var early gives you undefined without any error. Function declarations do work before their line, but the reader needs to scroll down to find out what's being called.

A variable used in its own initializer, such as const total = total + 1, is reported too. Unlike ESLint's no-use-before-define, this rule also checks enums, type aliases, and interfaces.

Configure#

Off by default. To turn it on:

bunfig.toml
[lint.rules]
"@typescript-eslint/no-use-before-define" = "error" # or "warn"

Every option, set to its default:

bunfig.toml
[lint.rules]
"@typescript-eslint/no-use-before-define" = ["error", {
  functions = true,
  variables = true,
  classes = true,
  enums = true,
  typedefs = true,
  ignoreTypeReferences = true,
  allowNamedExports = false,
}]

Examples#

example.ts3 problems
console.log(limit);
const limit = 10;

start(Mode.Fast);
function start(mode: Mode) {}

enum Mode {
  Fast,
  Slow,
}
example.tsNo problems
const limit = 10;
console.log(limit);

enum Mode {
  Fast,
  Slow,
}

function start(mode: Mode) {}
start(Mode.Fast);

Options#

OptionDefaultWhat it does
functionstrueReport function declarations that are used early. false allows every early use of them.
variablestrueWith false, a function can mention a var, let, or const that's declared below it. An early use in the same scope is still reported.
classestrueThe same as variables, for classes.
enumstrueThe same as variables, for enums.
typedefstrueReport type aliases and interfaces that are used early. This only has an effect with ignoreTypeReferences: false.
ignoreTypeReferencestrueAllow early uses in a type position, such as let user: User or typeof config.
allowNamedExportsfalseAllow export { name } above the declaration of name.

The string "nofunc" is short for { "functions": false }.

With functions: false, calling a function declaration early is allowed, because it's already defined when the file starts to run:

example.tswith { "functions": false }No problems
start();

function start() {}

By default, only the position in the file counts, even in a function that runs later:

example.ts1 problem
function isFull(count: number) {
  return count >= limit;
}

const limit = 10;
example.tswith { "variables": false }No problems
function isFull(count: number) {
  return count >= limit;
}

const limit = 10;

An early use in the same scope runs before the declaration, so it's still reported:

example.tswith { "variables": false }1 problem
console.log(limit);

const limit = 10;

Types don't exist when the code runs, so by default their order doesn't matter where they're used as types:

example.tsNo problems
let current: User;

type User = { name: string };
example.tswith { "ignoreTypeReferences": false }1 problem
let current: User;

type User = { name: string };
example.tswith { "ignoreTypeReferences": false, "typedefs": false }No problems
let current: User;

type User = { name: string };

With allowNamedExports: true, you can keep the export list at the top of the file:

example.tswith { "allowNamedExports": true }No problems
export { limit };

const limit = 10;