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