@typescript-eslint/no-magic-numbers
Disallow numbers that are used without a name
Also called typescript-eslint/no-magic-numbers, typescript/no-magic-numbers
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:
[lint.rules]
"@typescript-eslint/no-magic-numbers" = "error" # or "warn"Every option, set to its default:
[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#
function total(price: number) {
return price + price * 0.2No magic number: 0.2.;
}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 = 1No magic number: 1.,
}
type Level = 2No magic number: 2. | 3No magic number: 3.;
type First = [string, number][0No magic number: 0.];
class Client {
readonly retries = 4No magic number: 4.;
}Options#
| Option | Default | What it does |
|---|---|---|
ignore | [] | Numbers that are never reported. 1 doesn't cover -1. Write a bigint as a string: "1n". |
ignoreArrayIndexes | false | Allow a number as an index: items[0]. |
ignoreDefaultValues | false | Allow a number as a default value: function retry(times = 3) {}. |
ignoreClassFieldInitialValues | false | Allow a number as the initial value of a class field that isn't readonly. |
ignoreReadonlyClassProperties | false | Allow numbers in readonly class fields. |
ignoreEnums | false | Allow numbers in enum members. |
ignoreNumericLiteralTypes | false | Allow a type alias for a number or a union of numbers. |
ignoreTypeIndexes | false | Allow a number as an index into a type: Pair[0]. |
enforceConst | false | Report a number that initializes a let or a var. |
detectObjects | false | Also report numbers in object literals and numbers assigned to a property. |
Not reported with ignore: [0, 1]:
{ "ignore": [0, 1] }No problemsfunction last(items: string[]) {
return items.length === 0 ? undefined : items[items.length - 1];
}Not reported with ignoreArrayIndexes and ignoreDefaultValues:
{ "ignoreArrayIndexes": true, "ignoreDefaultValues": true }No problemsfunction pick(items: string[], count = 3) {
return [items[0], items.slice(count)];
}Not reported with ignoreEnums, ignoreNumericLiteralTypes, ignoreTypeIndexes and ignoreReadonlyClassProperties:
{ "ignoreEnums": true, "ignoreNumericLiteralTypes": true, "ignoreTypeIndexes": true, "ignoreReadonlyClassProperties": true }No problemsenum 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:
{ "ignoreClassFieldInitialValues": true }1 problemclass Client {
retries = 4;
readonly timeout = 5000No magic number: 5000.;
}Reported with enforceConst:
{ "enforceConst": true }1 problemlet timeout = 5000Number constants declarations must use const.;Both lines are reported with detectObjects:
{ "detectObjects": true }2 problemsconst config = { timeout: 5000No magic number: 5000. };
config.timeout = 3000No magic number: 3000.;