AphrodyBun GitHub

Runtime docs · Linter · Rules

@typescript-eslint/no-magic-numbers

Disallow numbers that are used without a name

A bare number in an expression doesn't say what it stands for. price * 0.2 could be a tax, a discount or a tip. If you write the same number in three places, you have to find all three to change it. A named const fixes both.

The rule doesn't report the number a variable is declared with, a value in an object literal, a number assigned to a property, the radix of parseInt() or a number in JSX. It reports every other number, including 0 and 1.

It's the TypeScript version of no-magic-numbers and takes the same options.

With bunfig.toml you can set either name. bun lint runs this rule in TypeScript files and no-magic-numbers 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-magic-numbers" = "error" # or "warn"

Every option, set to its default:

bunfig.toml
[lint.rules]
"@typescript-eslint/no-magic-numbers" = ["error", {
  ignore = [], # list of numbers or strings
  ignoreArrayIndexes = false,
  ignoreDefaultValues = false,
  ignoreClassFieldInitialValues = false,
  ignoreReadonlyClassProperties = false,
  ignoreEnums = false,
  ignoreNumericLiteralTypes = false,
  ignoreTypeIndexes = false,
  enforceConst = false,
  detectObjects = false,
}]

Examples

Reported:

function total(price: number) {
  return price + price * 0.2;
}

Not reported:

const TAX_RATE = 0.2;

function total(price: number) {
  return price + price * TAX_RATE;
}

Numbers in enums, types and class fields count too. All five are reported:

enum Status {
  Active = 1,
}

type Level = 2 | 3;

type First = [string, number][0];

class Client {
  readonly retries = 4;
}

Options

OptionDefaultWhat it does
ignore[]Numbers that are never reported. 1 doesn't cover -1. Write a bigint as a string: "1n".
ignoreArrayIndexesfalseAllow a number as an index: items[0].
ignoreDefaultValuesfalseAllow a number as a default value: function retry(times = 3) {}.
ignoreClassFieldInitialValuesfalseAllow a number as the initial value of a class field that isn't readonly.
ignoreReadonlyClassPropertiesfalseAllow numbers in readonly class fields.
ignoreEnumsfalseAllow numbers in enum members.
ignoreNumericLiteralTypesfalseAllow a type alias for a number or a union of numbers.
ignoreTypeIndexesfalseAllow a number as an index into a type: Pair[0].
enforceConstfalseReport a number that initializes a let or a var.
detectObjectsfalseAlso report numbers in object literals and numbers assigned to a property.

Not reported with ignore: [0, 1]:

function last(items: string[]) {
  return items.length === 0 ? undefined : items[items.length - 1];
}

Not reported with ignoreArrayIndexes and ignoreDefaultValues:

function pick(items: string[], count = 3) {
  return [items[0], items.slice(count)];
}

Not reported with ignoreEnums, ignoreNumericLiteralTypes, ignoreTypeIndexes and ignoreReadonlyClassProperties:

enum Status {
  Active = 1,
}

type Level = 2 | 3;

type First = [string, number][0];

class Client {
  readonly retries = 4;
}

With ignoreClassFieldInitialValues alone, the readonly field is still reported:

class Client {
  retries = 4;
  readonly timeout = 5000;
}

Reported with enforceConst:

let timeout = 5000;

Both lines are reported with detectObjects:

const config = { timeout: 5000 };
config.timeout = 3000;