]>
Commit | Line | Data |
---|---|---|
eb39fafa DC |
1 | # Suggest using `const` (prefer-const) |
2 | ||
3 | If a variable is never reassigned, using the `const` declaration is better. | |
4 | ||
5 | `const` declaration tells readers, "this variable is never reassigned," reducing cognitive load and improving maintainability. | |
6 | ||
7 | ## Rule Details | |
8 | ||
9 | This rule is aimed at flagging variables that are declared using `let` keyword, but never reassigned after the initial assignment. | |
10 | ||
11 | Examples of **incorrect** code for this rule: | |
12 | ||
13 | ```js | |
14 | /*eslint prefer-const: "error"*/ | |
eb39fafa DC |
15 | |
16 | // it's initialized and never reassigned. | |
17 | let a = 3; | |
18 | console.log(a); | |
19 | ||
20 | let a; | |
21 | a = 0; | |
22 | console.log(a); | |
23 | ||
609c276f TL |
24 | class C { |
25 | static { | |
26 | let a; | |
27 | a = 0; | |
28 | console.log(a); | |
29 | } | |
30 | } | |
31 | ||
eb39fafa DC |
32 | // `i` is redefined (not reassigned) on each loop step. |
33 | for (let i in [1, 2, 3]) { | |
34 | console.log(i); | |
35 | } | |
36 | ||
37 | // `a` is redefined (not reassigned) on each loop step. | |
38 | for (let a of [1, 2, 3]) { | |
39 | console.log(a); | |
40 | } | |
41 | ``` | |
42 | ||
43 | Examples of **correct** code for this rule: | |
44 | ||
45 | ```js | |
46 | /*eslint prefer-const: "error"*/ | |
eb39fafa DC |
47 | |
48 | // using const. | |
49 | const a = 0; | |
50 | ||
51 | // it's never initialized. | |
52 | let a; | |
53 | console.log(a); | |
54 | ||
55 | // it's reassigned after initialized. | |
56 | let a; | |
57 | a = 0; | |
58 | a = 1; | |
59 | console.log(a); | |
60 | ||
61 | // it's initialized in a different block from the declaration. | |
62 | let a; | |
63 | if (true) { | |
64 | a = 0; | |
65 | } | |
66 | console.log(a); | |
67 | ||
609c276f TL |
68 | // it's initialized in a different scope. |
69 | let a; | |
70 | class C { | |
71 | #x; | |
72 | static { | |
73 | a = obj => obj.#x; | |
74 | } | |
75 | } | |
76 | ||
eb39fafa DC |
77 | // it's initialized at a place that we cannot write a variable declaration. |
78 | let a; | |
79 | if (true) a = 0; | |
80 | console.log(a); | |
81 | ||
82 | // `i` gets a new binding each iteration | |
83 | for (const i in [1, 2, 3]) { | |
84 | console.log(i); | |
85 | } | |
86 | ||
87 | // `a` gets a new binding each iteration | |
88 | for (const a of [1, 2, 3]) { | |
89 | console.log(a); | |
90 | } | |
91 | ||
92 | // `end` is never reassigned, but we cannot separate the declarations without modifying the scope. | |
93 | for (let i = 0, end = 10; i < end; ++i) { | |
94 | console.log(a); | |
95 | } | |
96 | ||
97 | // `predicate` is only assigned once but cannot be separately declared as `const` | |
98 | let predicate; | |
99 | [object.type, predicate] = foo(); | |
100 | ||
101 | // `a` is only assigned once but cannot be separately declared as `const` | |
102 | let a; | |
103 | const b = {}; | |
104 | ({ a, c: b.c } = func()); | |
105 | ||
106 | // suggest to use `no-var` rule. | |
107 | var b = 3; | |
108 | console.log(b); | |
109 | ``` | |
110 | ||
111 | ## Options | |
112 | ||
113 | ```json | |
114 | { | |
115 | "prefer-const": ["error", { | |
116 | "destructuring": "any", | |
117 | "ignoreReadBeforeAssign": false | |
118 | }] | |
119 | } | |
120 | ``` | |
121 | ||
122 | ### destructuring | |
123 | ||
124 | The kind of the way to address variables in destructuring. | |
125 | There are 2 values: | |
126 | ||
127 | * `"any"` (default) - If any variables in destructuring should be `const`, this rule warns for those variables. | |
128 | * `"all"` - If all variables in destructuring should be `const`, this rule warns the variables. Otherwise, ignores them. | |
129 | ||
130 | Examples of **incorrect** code for the default `{"destructuring": "any"}` option: | |
131 | ||
132 | ```js | |
133 | /*eslint prefer-const: "error"*/ | |
134 | /*eslint-env es6*/ | |
135 | ||
136 | let {a, b} = obj; /*error 'b' is never reassigned, use 'const' instead.*/ | |
137 | a = a + 1; | |
138 | ``` | |
139 | ||
140 | Examples of **correct** code for the default `{"destructuring": "any"}` option: | |
141 | ||
142 | ```js | |
143 | /*eslint prefer-const: "error"*/ | |
144 | /*eslint-env es6*/ | |
145 | ||
146 | // using const. | |
147 | const {a: a0, b} = obj; | |
148 | const a = a0 + 1; | |
149 | ||
150 | // all variables are reassigned. | |
151 | let {a, b} = obj; | |
152 | a = a + 1; | |
153 | b = b + 1; | |
154 | ``` | |
155 | ||
156 | Examples of **incorrect** code for the `{"destructuring": "all"}` option: | |
157 | ||
158 | ```js | |
159 | /*eslint prefer-const: ["error", {"destructuring": "all"}]*/ | |
160 | /*eslint-env es6*/ | |
161 | ||
162 | // all of `a` and `b` should be const, so those are warned. | |
163 | let {a, b} = obj; /*error 'a' is never reassigned, use 'const' instead. | |
164 | 'b' is never reassigned, use 'const' instead.*/ | |
165 | ``` | |
166 | ||
167 | Examples of **correct** code for the `{"destructuring": "all"}` option: | |
168 | ||
169 | ```js | |
170 | /*eslint prefer-const: ["error", {"destructuring": "all"}]*/ | |
171 | /*eslint-env es6*/ | |
172 | ||
173 | // 'b' is never reassigned, but all of `a` and `b` should not be const, so those are ignored. | |
174 | let {a, b} = obj; | |
175 | a = a + 1; | |
176 | ``` | |
177 | ||
178 | ### ignoreReadBeforeAssign | |
179 | ||
180 | This is an option to avoid conflicting with `no-use-before-define` rule (without `"nofunc"` option). | |
181 | If `true` is specified, this rule will ignore variables that are read between the declaration and the first assignment. | |
182 | Default is `false`. | |
183 | ||
184 | Examples of **correct** code for the `{"ignoreReadBeforeAssign": true}` option: | |
185 | ||
186 | ```js | |
187 | /*eslint prefer-const: ["error", {"ignoreReadBeforeAssign": true}]*/ | |
188 | /*eslint-env es6*/ | |
189 | ||
190 | let timer; | |
191 | function initialize() { | |
192 | if (foo()) { | |
193 | clearInterval(timer); | |
194 | } | |
195 | } | |
196 | timer = setInterval(initialize, 100); | |
197 | ``` | |
198 | ||
199 | Examples of **correct** code for the default `{"ignoreReadBeforeAssign": false}` option: | |
200 | ||
201 | ```js | |
202 | /*eslint prefer-const: ["error", {"ignoreReadBeforeAssign": false}]*/ | |
203 | /*eslint-env es6*/ | |
204 | ||
205 | const timer = setInterval(initialize, 100); | |
206 | function initialize() { | |
207 | if (foo()) { | |
208 | clearInterval(timer); | |
209 | } | |
210 | } | |
211 | ``` | |
212 | ||
213 | ## When Not To Use It | |
214 | ||
215 | If you don't want to be notified about variables that are never reassigned after initial assignment, you can safely disable this rule. | |
216 | ||
217 | ## Related Rules | |
218 | ||
219 | * [no-var](no-var.md) | |
220 | * [no-use-before-define](no-use-before-define.md) |