ESLintのルールを全部読む
全部読んで、使うのか使わないのか、使うならどういう設定にするか、を全部考える。
airbnb-base を使いがちだったが自社のルールセット作るうえでは通ったほうが良い道なのではと思ったので、やる。
array-callback-return
ArrayやArray.prototypeに生えている関数(Arrany.fromやArray.prototype.everyなど)が引数にcallbackを取る場合に、callbackで必ずreturnを書くことを強要するルール。
// だめな例
/*eslint array-callback-return: "error"*/
var indexMap = myArray.reduce(function(memo, item, index) {
memo[item] = index;
// returnがない
}, {});
var foo = Array.from(nodes, function(node) {
if (node.tagName === "DIV") {
return true;
}
// node.tagName !== "DIV"の場合にreturnがない
});
var bar = foo.filter(function(x) {
if (x) {
return true;
} else {
return; // returnはあるが返り値に一貫性がない
}
});
Options
-
"allowImplicit"
- default: false
- trueの場合、返り値が必要なcallbackで、
return;
と書いて暗黙的にundefined
を返すのを許容する
-
"checkForEach"
- default: false
- trueの場合、
Array.prototype.forEach
のcallbackもこのルールの対象にする
-
"allowVoid"
- default: false
- trueの場合、
Array.prototype.forEach
のcallbackでreturn void;
を許容する。 - ※
"allowVoid"
は、"checkForEach"
が有効な場合のみ、有効
俺の設定
optionsなしの"error"
でよさそう。
constructor-super
子クラスの場合にconstructorでsuperを呼んでない場合にエラーになるルール。
eslint:recoomendedに含まれている。
Options
なし
俺の設定
"error"
でよい。
for-direction
forの継続条件と更新文が逆方向で無限ループになりそうな場合に指摘するルール。
eslint:recommendedに含まれている。
/*eslint for-direction: "error"*/
// 永遠に i < 10 なので無限ループ
for (var i = 0; i < 10; i--) {
}
// 永遠に i >= 10 なので無限ループ
for (var i = 10; i >= 0; i++) {
}
// 初期状態で i > 10 でないのでループしないはず。これも指摘してくれるの?
// 単純に条件と更新が合ってないから指摘してくれるだけかな、たぶん
for (var i = 0; i > 10; i++) {
}
// 条件文の左右が反対でもちゃんと指摘してくれるという例?
for (var i = 0; 10 > i; i--) {
}
// 変数でもいける?ええやん
const n = -2;
for (let i = 0; i < 10; i += n) {
}
Options
なし
俺の設定
"error"
getter-return
eslint:recommendedに含まれている。
getterでreturnを強制するルール。
以下、怒られるコード例。
/*eslint getter-return: "error"*/
p = {
get name(){
// no returns.
}
};
Object.defineProperty(p, "age", {
get: function (){
// no returns.
}
});
class P{
get name(){
// no returns.
}
}
Options
なし
俺の設定
TypeScriptを利用している場合は、TSのコンパイラーが指摘してくれるので無効にしても問題ないっぽいので、基本は"error"
、TypeScriptには"off"
でよさそう。
no-async-promise-executor
eslint:recommendedに含まれている。
new Promise(executor)
のexecutorにasync functionを禁止するルール。
理由は以下。
- async functionなexecutorがエラーを投げた場合、そのエラーはrejectを呼ばずにロストしてしまう。かなり、デバッグが難しい。
- そもそも、new Promiseが不要。
(async () { … })()
で十分。
俺の設定
"error"
no-await-in-loop
ループ内でawait
を許可しないルール。
ループ内にawait
があると直列で処理してしまうので、Promise.all
でやりましょう、みたいな感じ。
俺の設定
"error"
にしておいて、並列で処理すると量が多すぎる場合や、途中で失敗した場合に他のリクエストを中止したい場合は/* eslint-disable no-await-in-loop */
で都度無効にする対応がよさそう。
が、後者のケースを適切に処理してくれるnpmパッケージありそう。
no-class-assign
eslint:recommendedに含まれている。
ClassDeclaration
は変数を生成するので、その変数は変更可能(知らんかった)。
/*eslint-env es6*/
class A { }
A = 0;
これを禁止するルール。
俺の設定
"error"
no-compare-neg-zero
eslint:recommendedに含まれている。
-0
を===
で比較するのを警告するルール。理由は0
でも-0
でもtrueになるから。
もし、厳密に-0
かどうか比較したい場合は、Object.is(x, -0)
を使うといいっぽい。
俺の設定
"error"
no-cond-assign
eslint:recommendedに含まれる。
条件式で代入を禁止するルール。対象はif, for, while, do ... while。
Options
-
"except-parens"
は、()
で囲った場合のみOKとする。default値。 -
"always"
は、常に許可しない。
俺の設定
"error"
かな〜。"always"
を付けるまではないか、という感じ。
no-const-assign
eslint:recommendedに含まれる。
constで定義された変数に再代入市ている場合にエラーになるルール。ES2015未満の環境だと無視されるので。
俺の設定
"error"
。
TypeScriptの場合は、TSのコンパイラーが指摘するので"off"
でよさそう。
no-constant-binary-expression
なんかちょっと深そうだから一旦スキップ
no-constant-condition
eslint:recommendedに含まれている。
if (true)
みたいな定数を条件文にしたらエラー。
if, for, while, do ... while、三項演算子が対象。
Options
- checkLoops
- defaultはtrue。falseの場合、ループ(for, while, do ... while)では許可。
俺の設定
"error"
no-constructor-return
classのconstructorでreturnで値を返したらエラー。
俺の設定
"error"
no-control-regex
eslint:recommendedに含まれている。
ASCIIの0~31は目に見えない制御文字で、それらが正規表現に入っている場合はエラーにするルール。JSでそれらの文字を滅多に使うことはないので、ミスだろうということ。
具体的に以下がエラー。
-
\x00
~\x1F
-
\u0000
~\u001F
-
\u{0}
~\u{1F}
- 上記を使わずに直接 U+0000 ~ U+001F を入力
俺の設定
"error"
no-debugger
eslint:recommendedに含まれている。
debugger
命令を禁止するルール。昨今、デバッグ環境がよくなっていてあまり使われなくなっているし、本番環境にリリースしたら困るので、とのこと。
俺の設定
"error"
no-dupe-args
eslint:recommendedに含まれている。
関数の引数名が重複しているとエラー。
重複できることを知らなかった。。。以下の場合、2つ目のa
が出力される。
functions hoge(a, b, a) {
console.log(a);
}
hoge('a'); // undefined
俺の設定
"error"
TypeScriptの場合、TSのコンパイラーが許さないらしいので"off"
でOK。
no-dupe-class-members
eslint:recommendedに含まれる。
classの重複した名前のメンバーがある場合にエラー。
重複した場合、後勝ちになる。
俺の設定
"error"
TypeScriptの場合、TSのコンパイラーが怒ってくれるので"off"
でOK。
no-dupe-else-if
eslint:recommendedに含まれる
if/else if文の条件が重複している場合にエラーになる。
俺の設定
"error"
no-dupe-keys
eslint:recommendedに含まれる
オブジェクトのキー名が重複している場合にエラーになる。
俺の設定
"error"
no-duplicate-case
eslint:recommendedに含まれる。
switch文のcaseの条件が重複している場合にエラーになる。
俺の設定
"error"
no-duplicate-imports
同じモジュールからのimport文が複数行ある場合にエラーになる。
// incorrect
import { merge } from 'module';
import something from 'another-module';
import { find } from 'module';
// correct
import { merge, find } from 'module';
import something from 'another-module';
Options
includeExports
defaultはfalse。trueの場合、export文もこのルールの対象になる。
/*eslint no-duplicate-imports: ["error", { "includeExports": true }]*/
// incorrect
import { merge } from 'module';
export { find } from 'module';
// correct
import { merge, find } from 'module';
export { find };
俺の設定
"error"
eslint-plugin-importやeslint-plugin-unused-importsとかでauto fixしてくれてた気もする。後で調べる。
no-empty-character-class
eslint:recommendedに含まれる
正規表現で空の文字クラス(character class)がある場合、エラーになる。
// incorrect
var foo = /^abc[]/
制限事項
RegExpコンストラクタを使って文字列で正規表現を定義している場合、このルールでは検知できないので注意。
new RegExp("^abc[]")
俺の設定
"error"
no-empty-pattern
eslint:recommendedに含まれている
空のdestructingをエラーにするルール。
// incorrect
var {} = foo;
var [] = foo;
var {a: {}} = foo;
var {a: []} = foo;
function foo({}) {}
function bar([]) {}
function baz({a: {}}) {}
function qux({a: []}) {}
Options
allowObjectPatternsAsParameters
defaultはfalse。trueの場合、関数の引数では許可する。ただし、関数の引数でも空の配列でdestructingするケースはエラー。
/*eslint no-empty-pattern: ["error", { "allowObjectPatternsAsParameters": true }]*/
// correct
function foo({}) {}
var bar = function({}) {};
var bar = ({}) => {};
// incorrect
function baz([]) {}
俺の設定
"error"
no-ex-assign
eslint:recommendedに含まれている
catchしたerrorにcatch内で代入している場合にエラーになる。
try {
// code
} catch (e) {
e = 10;
}
俺の設定
"error"
参考記事に貼られていたやつ
IE6~8でcatchに変数のスコープがないので、catchした変数と同名の変数が上位のスコープにある場合、その変数にcatchしたエラーを代入しちゃうらしい。
もはや関係ないと思うけど、へーである。
no-fallthrough
eslint:recommendedに含まれる。
switch文でfallthrough(breakせずに次のcaseに繋げる)を禁止するルール。
Options
commentPattern
特定のコメントがある場合にルールを無視させるオプション。
/*eslint no-fallthrough: ["error", { "commentPattern": "break[\\s\\w]*omitted" }]*/
switch(foo) {
case 1:
doSomething();
// break omitted
case 2:
doSomething();
}
allowEmptyCase
空のケースはOKにするルール。
俺の設定
"error"
no-func-assign
eslint:recommendedに含まれる。
FunctionDeclaration(function foo() { ... }
)で定義された関数の他の変数への代入を禁止するルール。
TSではコンパイラーがチェックしてくれているらしいので、このルールを無効にしても大丈夫とのこと
function foo() {}
foo = bar; // error
俺の設定
"error"
no-import-assign
eslint:recommendedに含まれる。
import文よって束縛した変数に対する代入、インクリメントおよびデクリメントの禁止。
TSではコンパイラーが警告してくれるので、このルールは無効にしてもOK。ただ、Object.assignを使って代入するケースはTSでもカバーできない、とのこと。
import mod, { named } from "./mod.mjs"
import * as mod_ns from "./mod.mjs"
mod = 1 // ERROR: 'mod' is readonly.
named = 2 // ERROR: 'named' is readonly.
mod_ns.named = 3 // ERROR: The members of 'mod_ns' are readonly.
mod_ns = {} // ERROR: 'mod_ns' is readonly.
// Can't extend 'mod_ns'
Object.assign(mod_ns, { foo: "foo" }) // ERROR: The members of 'mod_ns' are readonly.
俺の設定
"error"
no-inner-declarations
ブロック内での変数・関数の定義を禁止するルール。
ES6前後で挙動が変わる部分で、ES6以降 or "use strict"
利用時はそこまで気にしなくてよい(スコープについて考えたのが久々すぎる)ので無効でもよさそう
俺の設定
設定しなくてよい。
no-invalid-regexp
eslint:recommendedに含まれる。
RegExp
コンストラクタで指定する正規表現が構文的におかしい場合にエラーになるルール。
RegExp
コンストラクタの第2引数のフラグは、最新のECMAScriptに準拠しており、パーサーの設定は見てないので注意。オプションのallowConstructorFlags
を使って、利用可能なフラグを指定することも可能。
俺の設定
"error"
no-irregular-whitespace
eslint:recommendedに含まれる。
以下の文字が含まれていた場合にエラーになるルール。目視だと分かりづらく、バグったときに発見しづらい文字。
\u000B - Line Tabulation (\v) - <VT>
\u000C - Form Feed (\f) - <FF>
\u00A0 - No-Break Space - <NBSP>
\u0085 - Next Line
\u1680 - Ogham Space Mark
\u180E - Mongolian Vowel Separator - <MVS>
\ufeff - Zero Width No-Break Space - <BOM>
\u2000 - En Quad
\u2001 - Em Quad
\u2002 - En Space - <ENSP>
\u2003 - Em Space - <EMSP>
\u2004 - Three-Per-Em
\u2005 - Four-Per-Em
\u2006 - Six-Per-Em
\u2007 - Figure Space
\u2008 - Punctuation Space - <PUNCSP>
\u2009 - Thin Space
\u200A - Hair Space
\u200B - Zero Width Space - <ZWSP>
\u2028 - Line Separator
\u2029 - Paragraph Separator
\u202F - Narrow No-Break Space
\u205f - Medium Mathematical Space
\u3000 - Ideographic Space
オプションを使うと、特定の場面ではルールを無効にすることもできる。
-
skipStrings
trueの場合、文字列定義内では許可(デフォルトで有効) -
skipComments
trueの場合、コメント内では許可 -
skipRegExps
trueの場合、正規表現リテラル内では許可 -
skipTemplates
trueの場合、テンプレートリテラル内では許可 -
skipJSXText
trueの場合、JSX Text内では許可
俺の設定
"error"
no-loss-of-precision
eslint:recommendedに含まれる。
桁数が多すぎて丸められ精度を失なうような数値リテラルを許可しないルール。
俺の設定
"error"
no-misleading-character-class
eslint:recommendedに含まれる。Suggestions対応ルール。
正規表現に複数のコードポイントを組み合わせた文字が含まれている場合に教えてくれるルール。
正規表現の文字クラスは、複数のコードポイントで作られた文字を扱えない。
/^[👶🏻]$/u.test("👶🏻"); //→ false
/^[👶🏽]$/u.test("👶🏽"); //→ false
オプション
allowEscape
trueの場合、\uXXXX
で記述している場合は許可。
俺の設定
"error"
no-new-native-nonconstructor
recommendedに含まれる。
SymbolやBigIntなど、newでインスタンス化できないコンストラクタでnewを使っているとエラーになるルール。
俺の設定
"error"
no-obj-calls
recommendedに含まれる。
ESが提供するグローバルオブジェクトで、コンストラクタとして利用できないものをコンストラクタや関数として呼び出そうとするとエラーになるルール。
- ES5: Math, JSON
- ES2015: Reflect
- ES2017: Atomics
- ES I18n: Intl
TypeScriptを利用している場合、TSのコンパイラがエラーを吐くのでこのルールは無効にしてもOK。
俺の設定
JSでは"error"
。TSでは指定しない。
no-promise-executor-return
Suggestions対応ルール。
Promiseのexecutorで値をreturnするのを禁止するルール。
new Promise
でコンストラクタの引数に渡す関数を、executorと呼ぶらしい。executorで値をreturnしても無視されるだけなので、このルールが教えてくれる。
オプション
allowVoid
trueの場合、void
は許可。
俺の設定
"error"
no-prototype-builtins
recommendedに含まれるルール。Suggestions対応ルール。
hasOwnPropertyなどObject.prototypeに生えているメソッドをobj.hasOwnProperty(...)
のようにオブジェクトのメソッドとして呼ぶのを禁止するルール。
どういうときに困るかというと、例えばJSON.parseでJSON文字列からオブジェクト生成する場合に{"hasOwnProperty":1}
のようなデータが入っていると、obj.hasOwnProperty(...)
はクラッシュしてしまう。Object.prototype.hasOwnProperty.call(obj, ...)
で呼びましょう、という昔からある教え。
俺の設定
"error"
no-self-assign
recommendedに含まれるルール。
両サイド同じ変数の代入を禁止するルール。
foo = foo
[bar, baz] = [bar, baz]
オプション
props
trueの場合、プロパティへの代入は許可。
// ["error", {"props": true}] の場合、以下はOK
obj.a = obj.a;
俺の設定
"error"
no-self-compare
両サイドが全く同じ場合の比較を禁止するルール
x === x
NaNかどうか判定する方法(NaN同士は===
で比較してもfalseになる)として利用することが唯一有効な利用方法だが、Number.isNaNを使う方が意図が明確でよいと思うので、禁止でよい。
俺の設定
"error"
no-setter-return
recommendedに含まれる。
Setterで値をreturnするのを禁止するルール。
Setterで値をreturnしても無視されるだけなので。
TypeScriptの場合、コンパイラーがエラーにしてくれるので、このルールは無効にしてもOK.
俺の設定
JSでは"error"
、TSでは指定しない・無効にする。
no-sparse-arrays
recommendedに含まれる
sparse arrayを禁止するルール。
sparse arrayとは、以下のように配列リテラル内にカンマだけ書いて、まばらな(sparse)な状態の配列のこと。
items = [,,] // length === 2。 items[0]、items[1]はundefined。
※個人的な感想:[,,]
で要素2つなの、直感的じゃなくね?と思ったが、[]
が0, [,]
が1, [,,]
が2, ... と考えると自然だった。
以下のように値がある要素とない要素を混ぜることができるが、これが意図お通りなのかタイポなのか、判断が難しいので、禁止でよいと思う。
var colors = [ "red",, "blue" ];
最後にカンマがあるパターンは、無視される。(これも意味ないと思うから、エラーでいいのでは?)
[1, 2, ] // これはエラーにならない。length === 2になるので。
俺の設定
"error"
no-template-curly-in-string
テンプレートリテラルのプレースホルダーを普通の文字列リテラルで使うのを禁止するルール。
"Hello ${name}!"; // error!!!
俺の設定
"error"
no-this-before-super
recommendedに含まれる。
コンストラクタ内でsuper()
を呼ぶ前にsuper, thisを使うことを禁止するルール。
参照エラーを防ぐため。
俺の設定
"error"
no-undef
recommendedに含まれる。
未定義の変数へアクセスするのを禁止するルール。
/* globals: ... */
コメントか、ESLintのglobals
で指定した変数は対象外。
このルールはread-onlyなグローバル変数への代入を禁止しないので、禁止したい場合は、別途no-global-assign
ルールが必要。
また、このルールはグローバル変数への再定義も禁止しないので、禁止したい場合はno-redeclare
ルールが必要。
TypeScriptの場合、コンパイラーがこのルールを代替してくれるので、指定しなくてもOK。
オプション
typeof
trueの場合、typeof内でグローバル変数を指定すると警告してくれる。デフォルトはfalse。
俺の設定
JSの場合は"error"
、TSの場合は無指定 or 無効。
no-unexpected-multiline
recommendedに含まれる。
自動セミコロン挿入にならない改行を禁止するルール。
JSではセミコロンは任意で、省略した場合に改行時に自動でセミコロンが挿入された状態と解釈される仕様だが、例外があって、改行した2つの文が結合した状態で解釈される場合がある。
え、その例外って何、って?それは自分で調べる方があなたのためになると思いますし、このルールを有効にすればそんなこと考えなくてよいのでおすすめです。
俺の設定
"error"
no-unmodified-loop-condition
ループの条件内の変数がループ内で変更されていない場合にエラーになるルール。
以下のように、関数呼び出しの引数に使われている場合も「変更されていない」判定になり、エラーになる。
// 以下はエラー
while (node) {
doSomething(node);
}
俺の設定
"error"
ループ内で変更している方がコードとしてわかりやすいし、変更しないようなコードを書いたことが今まで無いので、recommendedには入ってないらしいがエラーでいいと思う。
no-unreachable
recommendedに含まれる。
return, throw, continue, break以降の到達することのないコードを禁止するルール。
以下のような、サブクラスのconstructorでsuper()を呼ばない場合のフィールド定義もunreachableなのでエラーになる。フィールドはsuper()呼び出し後にインスタンスに追加されるため。
/*eslint no-unreachable: "error"*/
class C extends B {
#x; // unreachable
#y = 1; // unreachable
a; // unreachable
b = 1; // unreachable
constructor() {
return {};
}
}
TypeScriptにおいては、tsconfig.jsonでallowUnreachableCode: false
にすると、TSコンパイラーでのこのチェックを行ってくれる。
俺の設定
JSの場合は"error"
。
TSの場合は@tsconfig/strictest
を使うことが多く、allowUnreachableCode: false
になっているので指定なし・無効、でよさそう。
no-unreachable-loop
1度しかbody部が実行されないループを禁止するルール。
(静的コードパス解析での指摘で制限があるので、recommendedに入ってない?)
オプション
ignores
このルールを無効にするループを指定できる。
俺の設定
"error"
no-unsafe-finally
recommendedに含まれる
unsafeなfinallyを禁止するルール。
finally内でのreturn, throw, break, continueの呼び出しは、try/catch内でのそれらの呼び出しを上書きしてしまうので、意図しない挙動になる可能性が高い。
// We expect this function to return 1;
(() => {
try {
return 1; // 1 is returned but suspended until finally block ends
} catch(err) {
return 2;
} finally {
return 3; // 3 is returned before 1, which we did not expect
}
})();
// > 3
俺の設定
"error"
no-unsafe-negation
recommendedに含まれる。Suggestions対応されている。
比較演算の左オペランドで否定を使うのを禁止するルール。
例えば、!key in object
は、key in object
の否定とは評価されず、key
を否定したものをin object
で評価する。!(key in object)
のように書く必要がある。
TypeScriptではコンパイラが指摘してくれるので、無効にしてもOK。
オプション
(WIP)
俺の設定
JSでは"error"
、TSでは指定しないor無効にする。
(が、TSではfixまでやってくれないとしたら有効にしといてもいいか🤔)
no-unsafe-optional-chaining
recommendedに含まれる。
undefinedが許与されないコンテキストでOptional Chainingするのを禁止するルール。
1 in obj?.foo; // TypeError
with (obj?.foo); // TypeError
for (bar of obj?.foo); // TypeError
bar instanceof obj?.foo; // TypeError
const { bar } = obj?.foo; // TypeError
var obj = undefined;
(obj?.foo)(); // TypeError
(obj?.foo).bar; // TypeError
オプション
disallowArithmeticOperators
trueの場合、算術演算でOptional Chainingを使うのを禁止する。undefinedと算術演算すると、結果がNaNになるため。
デフォルトはfalse。
// obj?fooがundefinedの場合、結果がNaNになる
obj?.foo + bar;
俺の設定
["error", { disallowArithmeticOperators: true }]
TSで警告してくれそうな予感がしたが、特に記述なかったので気になった🤔
no-unused-private-class-members
recommendedに含まれる。
class内に利用していないprivateなメンバーが定義されている場合にエラー。
v8.1.0からのルールとのこと。結構最近だ。
俺の設定
"error"
no-unused-vars
recommendedに含まれる。
宣言したが使われていない値を禁止するルール。おなじみのルール。
exportedコメント
CommonJS・ES Module環境以外では、var
はグローバル変数を定義するのに利用できる。
/* exported 変数名 */
で、そのようなグローバルに定義されている値を指定でき、このルールの対象外にできる。
ま、CommonJS・ES Module以外の環境で開発することはあんまりないと思うけど!
Options
vars
"all"
or "local"
"all"
がデフォルトで、全ての値がこのルールの対象になる。"local"
の場合は、ローカル変数のみを見て、グローバル変数は見ない。
varsIgnorePattern
var
で定義する値の中で、このルールの対象外にするパターンを正規表現で指定できる。
args
"after-used"
, "all"
or "none"
after-used
利用されている引数のうち、最後に定義されている引数より後ろにある引数のみをこのルールの対象にする。
下記コードでは、barより後ろの引数(baz, qux)がエラーになる。
/*eslint no-unused-vars: ["error", { "args": "after-used" }]*/
// 2 errors, for the parameters after the last used parameter (bar)
// "baz" is defined but never used
// "qux" is defined but never used
(function(foo, bar, baz, qux) {
return bar;
})();
all
全ての引数をチェック。
none
引数をチェックしない。
argsIgnorePattern
チェックしない引数のパターンを正規表現で指定できる。例えば、_
で始まる引数は無視するとか。/*eslint no-unused-vars: ["error", { "argsIgnorePattern": "^_" }]*/
caughtErrors
"all"
or "none"
catchブロックで捕捉したエラーをチェックするかどうか。"all"
はチェックする、"none"
はチェックしない。
"all"
がデフォルト。
caughtErrorsIgnorePattern
catchブロックで捕捉したエラーの中で、無視するパターンを正規表現で指定できる。
destructuredArrayIgnorePattern
配列の分割代入で、このルールが無視するパターンを正規表現で指定できる。
ignoreRestSiblings
デフォルトはfalse。trueの場合、Object rest propertyを無視する。
var { foo, ...rest } = data;
みたいなときに、fooを除くプロパティをrestに入れたいという要件の場合、fooはただ捨てたいだけでエラーがノイズになる。そういうときに有用。
ignoreClassWithStaticInitBlock
デフォルトはfalse。
trueの場合、Static initialization blockをルールの対象外にする。
reportUsedIgnorePattern
デフォルトはfalse。
trueの場合、varsIgnorePattern, argsIgnorePattern, caughtErrorsIgnorePattern, destructuredArrayIgnorePatternで指定したパターンにマッチした部分をレポートしてくれる。
俺の設定
とりあえず、"error"
。
v0.0.9からあるルールだけあって、オプションが多いのでどれかが必要になる可能性もありそう。
no-use-before-define
値を定義前に使うのを禁止するルール。おなじみ。
Options
functions
関数をこのルールの対象にするか、どうか。デフォルトはtrue
classes
クラスをこのルールの対象にするかどうか。デフォルトはtrue
variables
値をこのルールの対象にするかどうか。デフォルトはtrue
allowNamedExports
trueの場合は、export { … };
をこのルールの対象外とする。
These references are safe even if the variables are declared later in the code.
とのこと。
MDNにも以下のように記述されている。
エクスポート宣言は一時的なデッドゾーンのルールには従いません。X という名前自体が宣言される前に、そのモジュールが X をエクスポートすることを宣言することができます。
デフォルトはfalse。
俺の設定
["error", { allowNamedExports: true }]
no-useless-assignment
利用しない代入を禁止するルール。
let id = "x1234"; // this is a "dead store" - this value ("x1234") is never read
id = generateId();
doSomethingWith(id);
俺の設定
"error"
あんまり怒られることはない気がするけども。
no-useless-backreference
recommendedに含まれる。
backreference=後方参照。
後方参照は、前回キャプチャグループによって一致したのと同じテキストに一致する方法です。
/(b)\1/i.test("bB"); // true
以下のような、ECMAScriptの仕様的には正しいがマッチしない後方参照を禁止するルール。
- 論理和内の後方参照(ex:
/(a)|\1b/
) - グループより先にある後方参照(ex:
/\1(a)/
) - グループ内の後方参照(ex
/(\1)/
) - 否定の先読みないにあるグループの後方参照(ex:
/a(?!(b)).\1/
)
俺の設定
"error"
require-atomic-updates
awaitやyieldによるレースコンディションを招く代入を禁止するルール。
例えば、以下のコード。
let totalLength = 0;
async function addLengthOfSinglePage(pageNum) {
totalLength += await getPageLength(pageNum);
}
Promise.all([addLengthOfSinglePage(1), addLengthOfSinglePage(2)]).then(() => {
console.log('The combined length of both pages is', totalLength);
});
上記コードの最終的なtotalLengthの値は、await getPageLength(1) + await getPageLength(2)
になる気がする。しかし、totalLength += await getPageLength(pageNum);
は、まずtotalLength
をreadするため、実際はtotalLength = 0 + await getPageLength(pageNum)
と同義になる。結果として、getPageLength(1)
とgetPageLength(2)
の2つの中で後でresolveした方が最終的なtotalLength
の値になってしまう。
上記のコードでrace conditionを避けるためには、以下のようにawait後にtotalLengthをreadするようにする。
// totalLengthをawaitの後でreadするように変える
totalLength = await getPageLength(pageNum) + totalLength;
// こちらでもOK
const length = await getPageLength(pageNum);
totalLength += length;
または、以下のようにtotalLengthがimmutableになるようにコードを書く(個人的には絶対こっち)。
Promise.all([getPageLength(1), getPageLength(2)]).then(pageLengths => {
const totalLength = pageLengths.reduce((accumulator, length) => accumulator + length, 0);
console.log('The combined length of both pages is', totalLength);
});
具体的にどのような場合にエラーになるか
変数への代入の場合
async関数 or generator関数内で、以下のような実行フローを検出した場合にエラーになる。
- 変数のread
- yield or awaitにより関数が中断
- 関数が再開後、1の変数に値を代入
以下の場合はエラーにならない。
- 2と3の間で変数Aを再度readしている
- 関数Bが中断している間に変数Aにアクセスできない(例: 変数Aがローカル変数)
以下、怒られるコード例。
/* eslint require-atomic-updates: error */
let result;
async function foo() {
result += await something; // error
}
async function bar() {
result = result + await something; // error
}
async function baz() {
result = result + doSomething(await somethingElse); // error
}
async function qux() {
if (!result) {
result = await initialize(); // error
}
}
function* generator() {
result += yield; // error
}
プロパティへの代入の場合
async関数 or generator関数内で、以下のような実行フローを検出した場合にエラーになる。
- 変数またはオブジェクトのプロパティのread
- yield or awaitにより関数が中断
- 関数が再開後、オブジェクトのプロパティに値を代入
変数代入と似ているけど、3の代入が必ずしも1のプロパティと同じである必要がないので、より厳格。
例えば、以下のコード。obj.done
のread後(①)、await getSomething()
で関数が中断(②)、obj.something
にawait getSomething()
の返り値を代入(③)しているため、エラーになる。
理由は、await getSomething()
で関数を中断している間にobj.done
の値が変わる可能性があるから。
/* eslint require-atomic-updates: error */
async function foo(obj) {
if (!obj.done) {
obj.something = await getSomething(); // error
}
}
以下が正しいコード。これは気づくのが難しいので、ありがたいかもしれない。
/* eslint require-atomic-updates: error */
async function foo(obj) {
if (!obj.done) {
const tmp = await getSomething();
if (!obj.done) {
obj.something = tmp;
}
}
}
Options
allowProperties
trueの場合、「プロパティへの代入」をこのルールの対象外にできる。デフォルトはfalse。
俺の設定
"error"