@typescript-eslint/no-redeclare

Disallow declaring the same name twice in one scope

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

var lets you declare a name a second time without an error. The second declaration is the same variable as the first, so it overwrites a value that other code may still need. It's usually a copy and paste mistake, or two parts of a long function that picked the same name.

This is no-redeclare for TypeScript. It knows about function overloads and the declarations TypeScript merges on purpose, such as two interfaces with the same name.

With bunfig.toml you can set either name. bun lint runs this rule in TypeScript files and no-redeclare in JavaScript files, so nothing is reported twice. With an ESLint config, use it in place of no-redeclare, which reports those.

Configure#

Off by default. To turn it on:

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

Every option, set to its default:

bunfig.toml
[lint.rules]
"@typescript-eslint/no-redeclare" = ["error", {
  builtinGlobals = true,
  ignoreDeclarationMerge = true,
}]

Examples#

example.ts1 problem
function price(items: number[]) {
  var total = items.length;
  for (const item of items) {
    var total = item;
  }
  return total;
}
example.tsNo problems
function price(items: number[]) {
  let total = items.length;
  for (const item of items) {
    total += item;
  }
  return total;
}

Overloads and merged declarations aren't reported either:

example.tsNo problems
function parse(input: string): number;
function parse(input: number): number;
function parse(input: string | number) {
  return Number(input);
}

interface Options {
  verbose: boolean;
}
interface Options {
  color: boolean;
}

class Logger {}
namespace Logger {
  export const level = "info";
}

Options#

OptionDefaultWhat it does
builtinGlobalstrueAlso report a name that's already a global, such as Object. This applies to the top level of a script and to /* global */ comments. The top level of a module is its own scope.
ignoreDeclarationMergetrueAllow the declarations TypeScript merges: interfaces with interfaces, namespaces with namespaces, and one class, function or enum with namespaces. A class also merges with interfaces.

Reported by default, and allowed with builtinGlobals: false:

example.ts1 problem
/* global process */

console.log(process.platform);
example.tswith { "builtinGlobals": false }No problems
/* global process */

console.log(process.platform);

Reported with ignoreDeclarationMerge: false:

example.tswith { "ignoreDeclarationMerge": false }1 problem
interface Options {
  verbose: boolean;
}
interface Options {
  color: boolean;
}

Two enums with the same name are always reported:

example.ts1 problem
enum Level {
  Info,
}
enum Level {
  Error = 1,
}