@typescript-eslint/no-shadow

Disallow a declaration that hides one with the same name in an outer scope

Also called typescript-eslint/no-shadow, typescript/no-shadow

When an inner scope declares a name that an outer scope already has, you can't reach the outer one from there. A reader who saw the outer declaration first mistakes the inner uses for it, and a line moved from one scope to the other silently refers to a different variable.

It's the TypeScript version of no-shadow and takes the same options. Only the hoist default differs. It's "functions-and-types" here and "functions" there.

With bunfig.toml you can set either name. bun lint runs this rule in TypeScript files and no-shadow in JavaScript files, so nothing is reported twice. With an ESLint config, turn on only one of the two.

Configure#

Off by default. To turn it on:

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

Every option, set to its default. The ones that are commented out are unset by default.

bunfig.toml
[lint.rules]
"@typescript-eslint/no-shadow" = ["error", {
  allow = [], # list of strings
  builtinGlobals = false,
  # "all", "functions", "functions-and-types", "never" or "types"
  # hoist = "functions-and-types",
  ignoreOnInitialization = false,
  ignoreTypeValueShadow = true,
  ignoreFunctionTypeParameterNameValueShadow = true,
}]

Examples#

example.ts1 problem
const timeout = 1000;

function retry(action: () => void) {
  const timeout = 50;
  setTimeout(action, timeout);
}
example.tsNo problems
const timeout = 1000;

function retry(action: () => void) {
  const delay = 50;
  setTimeout(action, delay);
}

A type parameter hides a type, and an enum member hides a variable inside the enum:

example.ts2 problems
type Item = { id: number };
function first<Item>(items: Item[]) {
  return items[0];
}

const Low = 10;
enum Priority {
  Low,
  High = Low + 1,
}

Options#

OptionDefaultWhat it does
allow[]Names that may hide an outer declaration.
builtinGlobalsfalseAlso report a name that hides a global, such as Array.
hoist"functions-and-types"When to report a name that comes before the outer declaration it hides. See below.
ignoreOnInitializationfalseAllow it in a callback that's part of the outer variable's initializer.
ignoreTypeValueShadowtrueAllow a value to have the name of an outer type, and a type the name of an outer value.
ignoreFunctionTypeParameterNameValueShadowtrueAllow a parameter in a function type or signature to have the name of an outer variable.

builtinGlobals#

Reported with builtinGlobals: true:

example.tswith { "builtinGlobals": true }1 problem
function first(Array: string[]) {
  return Array[0];
}

hoist#

ValueOuter declarations that count when they come after the inner name
"all"All.
"functions"Function declarations.
"types"Interfaces and type aliases.
"functions-and-types"All three.
"never"None.

Here the outer port is a const that comes later, so this is allowed by default:

example.tsNo problems
function listen() {
  const port = 3000;
  return port;
}

const port = 8080;

It's reported with hoist: "all":

example.tswith { "hoist": "all" }1 problem
function listen() {
  const port = 3000;
  return port;
}

const port = 8080;

ignoreOnInitialization#

Not reported with ignoreOnInitialization: true:

example.tswith { "ignoreOnInitialization": true }No problems
declare const users: { active: boolean }[];

const user = users.find(user => user.active);

ignoreTypeValueShadow#

A type and a value with the same name don't get in each other's way, so this is allowed by default:

example.tsNo problems
type Config = { port: number };

function start() {
  const Config = { port: 3000 };
  return Config;
}

ignoreFunctionTypeParameterNameValueShadow#

A function type's parameter is only a label. Set the option to false to report it:

example.tswith { "ignoreFunctionTypeParameterNameValueShadow": false }1 problem
const id = 1;

type Lookup = (id: number) => string;