6時だョ!!全員集合!!

Rails・JavaScrictを中心にアウトプットします。

2022年5月3日 りあクト! 第6章 stylelint (p.74~)

stylelintとは

stylelintはCSSのlinterです。

使用するには4つのパッケージをインストールします。

  • stylelint ... stylelint本体です。
  • stylelint-config-standard ... stylelint公式による標準の共有設定です。
  • stylelint-order ... stylelintの並び順に関するルールセットのプラグインです。
  • style-config-recess-order ... RECESSに基づくCSSの並び替えのための共有設定です。
yarn add -D stylelint stylelint-config-standard stylelint-order stylelint-config-recess-order

(typesync) ← 型定義ファイルの読み込みはpackage.jsonのpreinstallに設定してあるのでインストール前に自動で走ります。
yarn  ← yarn installの省略

stylelint導入後の設定

プロジェクトルートに.stylelintrc.jsを配置し、設定を追記します。

.stylelintrc.js
  module.exports = {
    // extendsに共有設定を書く
    extends: [
      'stylelint-config-standard',
      // リセスはTwitterが提供していたCSSのコード品質ツール
      // リセスをstylelint-orderに移植したものが以下の設定。
      'stylelint-config-recess-order'
    ],
    // pluginsにプラグインルールを書く
    plugins: [
      'stylelint-order'
    ],
    ignoreFiles: [
    // node_modulsディレクトリ配下にあるCSSを対象外する。
      '**/node_modules/**'
    ],
    // rulesはリンターが何を探し、何を訴えるかを決定します。
    // Stylelint には 170 以上のルールが組み込まれています。 
    // デフォルトではどのルールもオンになっておらず、
    // デフォルト値もありません。各ルールを有効にするには、明示的に設定する必要があります。
    // キーはルールの名前、値はルールの設定です。
    rules: {
      'string-quotes': 'single'
    }
  }; 
  • stylelint-config-standardは公式が提供している標準の共有設定です。
  • 今回採用しませんでしたがstylelint-config-recommendedの方が広く使用されています。
  • style-config-standardは、stylelint-config-recommendedを拡張しつつGoogleAirbnb が定めた CSS スタイルガイドを適用した厳格な設定です。

VSCodeのsettings.jsonに設定する

設定を追加します。

{
+ "css.validate": false,
+ "less.validate": false,
+ "scss.validate": false,
  "editor.codeActionsOnSave": {
  "source.fixAll.eslint": true,
+ "source.fixAll.stylelint": true
  },
  "editor.formatOnSave": false,
  ︙

package.jsonにnpm scriptsの登録をする

ESlintやPrettierとまとめて走るようにします。

  "scripts": {
...
    "lint": "npm run -s lint:style; npm run -s lint:es",
    "lint:fix": "npm run -s lint:style:fix && npm run -s lint:es:fix",
    "lint:es": "eslint 'src/**/*.{js,jsx,ts,tsx}'",
    "lint:es:fix": "eslint --fix 'src/**/*.{js,jsx,ts,tsx}'",
    "lint:conflict": "eslint-config-prettier 'src/**/*.{js,jsx,ts,tsx}'",
    "lint:style": "stylelint 'src/**/*.{css,less,sass,scss}'",
    "lint:style:fix": "stylelint --fix 'src/**/*.{css,less,sass,scss}'",
    "preinstall": "typesync || :"
  },
  • ESLintは"lint:es"というオプション名に変更し、stylelintは"stylelint:es"としてオプションを追加します。
  • 元々"lint"として設定していたESLintのオプションはlint:esとstylelint:esオプションをまとめて実行出来るように変更します。
--fix

ESLint や stylelint を --fix モードで走らせると、簡単なルール違反は自動で修正してくれますが、直しきれない複雑なものは手動で修正する必要があります。

Git Hooks

特定のアクションが発生したときに任意のスクリプトを走らせるGitのしくみです。 Git Hooksを管理するsimple-Git-hooksというツールがあります。 huskyというツールの方が有名です。しかし、5系以降に複雑な設定が増えた為、現在はsimple-Git-hooksも使われています。

上記のツールを用いてGitのコミットやプッシュ前後にLintのスクリプトを実行する設定をすることが出来ます。

参考

りあクト! TypeScriptで始めるつらくないReact開発 第3.1版【Ⅱ. React基礎編】 p.74~

Configuration

2022年5月2日 Rails開発者が採用面接で聞かれる想定Q&A 53問(翻訳)を深ぼる(Q1〜Q10)

基本的な用語

コレクション

コレクションとは,いくつかのオブジェクトをまとめて取り扱うための「容器」として振る舞うオブジェクトです。Rubyの標準ライブラリはいくつかのコレクション・クラスを提供しています。代表的なものはArray(配列)とHash(ハッシュまたは連想配列)です。 引用

Rubyにおけるオブジェクト

オブジェクト指向言語におけるオブジェクトとは、クラスのインスタンスのことです。 全てのインスタンス(オブジェクト)を作るクラスはclassクラスを継承しています。 class自体がclassクラスのインスタンスです。

irb(main):002:0> Class.class
=> Class

オブジェクト指向言語

オブジェクトを基本的な単位としてプログラムをつくることが出来る言語です。 オブジェクト指向とはそのプログラミングの性質のことをいいます。

オブジェクト指向言語ではオブジェクトの雛形であるクラス(class)やプロトタイプ(prototype)、および内部のメソッド(method)やプロパティ(property)を定義する構文や、オブジェクトのインスタンス化、メソッド呼び出しなどの機能が提供されています。

インスタンス変数

class User
  def initialize(name)
    @name = name
  end
  
  # クラス内で定義したインスタンス変数は、
  # クラス内で自由に使うことができます。
  def hello
    puts "Hello, I am #{@name}"
  end
end

user = User.new('Alice')
user.hello # => Hello, I am Alice
class User
  # インスタンス変数を参照するためには、ゲッターを定義する
  attr_reader :name
  def initialize(name)
    @name = name
  end
  
  def hello
    puts "Hello, I am #{@name}"
  end
end

user = User.new('Alice')
user.hello # => Hello, I am Alice
puts user.name # => Alice

ローカル変数

  • ローカル変数とは、メソッドやブロックの内部で作成される変数です。
  • @がついていない変数です。
  • ブロックの外では使用出来ません。

sendメソッド

sendとは、レシーバの持っているメソッドを引数に渡すことで呼び出してくれるメソッドです。

obj.hello  #=> 'hello'
obj.send(:hello) #=> 'hello'
  • objは何かのクラスのインスタンスで、そのクラス内でhelloメソッドが定義されているという前提です。
  • objはhelloメソッドを持つため、sendを経由して実行することが出来ます。

デザインパターン

デザインパターンとは、「よく出会う問題とそれにうまく対処するための設計」をまとめたものです。

引用

セッター・ゲッター

Rubyではゲッター(getter)を用いてインスタンス変数にアクセスでき、セッター(setter)を用いてインスタンス変数に値を設定できます。

セッター(クラス内)

  def name_change=(name)
      @name = name
  end

クラス内で上記のようにセッターを定義することで値の変更を出来るようになります。 attr_writerやアクセサーを定義することで、上記の定義をせずにセッターが使用できます。

class User
  attr_reader :name
  attr_writer :name
  def initialize(name)
    @name = name
  end
  
  def hello
    puts "Hello, I am #{@name}"
  end
end

user = User.new('Alice')
# インスタンスは、所属しているクラスに定義してあるメソッドを呼び出すことができる
user.hello # => Hello, I am Alice
puts user.name # => Alice
user.name ="YUKI";
user.hello

ActiveRecordを継承したモデルのインスタンスの場合は、生成した段階でアクセサーが自動的に定義されるため、セッターやゲッターを自分で定義しなくても使用することが出来ます。

irb(main):001:0> @user = User.new()
=> #<User id: nil, email: nil, crypted_password: nil, salt: nil, created_at: nil, updated_at: nil, first_name: nil, last_name: nil, avatar: nil, reset_password_token: nil, reset_password_token_expires_at: nil, reset_password_email_sent_at: nil, access_count_to_reset_password_page: 0, role: "general">
# respond_to?を使うことで、オブジェクトがメソッドを持つかを判定できます。
irb(main):002:0> @user.respond_to?(:email)
=> true
irb(main):003:0> @user.respond_to?(:email=)
=> true

参考

デザインパターンの基本 Rails開発者が採用面接で聞かれる想定Q&A 53問(翻訳) 7 Design Patterns to Refactor MVC Components in Rails

2022年4月30日 アルゴ式 番外編

アルゴ式とは

プログラミングを解くドリルが提供されているWEBサービスである。by yano

今回の問題

配列の全探索 1 Image from Gyazo

Ryuji's answer

JavaScript

function main(input) {
const args = input.split("\n");
  const inputArray = args.map((n) => n.split(" "));
  const array1 = args[0].split(" ").map((n) => parseInt(n, 10));
  const N = array1[0];
  const V = array1[1];
  const A = args[1].split(" ").map((n) => parseInt(n, 10));

  const found = A.find(e => e === V);

  found ? console.log("Yes") : console.log("No");


}

main(require('fs').readFileSync('/dev/stdin', 'utf8'));
  • ArrayのメソッドをMDNに見にいきました。
  • メソッドを閲覧している時にfindメソッドが目に止まりました。
  • Node.jsでSequelizeのfindOneメソッドでログインの処理を実装したときにデータベースに登録してあるメールアドレスと入力したメールアドレスを照合する時のロジックが頭の中で浮かび、findメソッドでできそうだと仮説を立てて挙動を確認したら今回の問題に使えると思いました。
  • Aの配列の中からVに一致する値をfound変数に代入するようにしました。
  • 三項演算子を使い実行結果を条件分岐し提出したところLGTMでした。

Yano's answer

N, V = gets.split(' ').map!(&:to_i)
A = gets.split(' ').map!(&:to_i)

if A.include?(V)
  puts "Yes"
else
  puts "No"
end

pメソッドを使用するとテストが通らず不正解になるため、注意です。

N, V = gets.split(' ').map!(&:to_i)
A = gets.split(' ').map!(&:to_i)

puts A.include?(V) ? "Yes" : "No"

三項演算子パターンの場合、上記で正解となります。

map!(&:to_i)

以下とほぼ同義です。 map!とするとレシーバを破壊的に変更することができます。

.map {|n| n.to_i}

Yuki's answer

JavaScript

function main(input) {
  const args = input.split("\n");
  const inputArray = args.map((n) => n.split(" "));
  const array1 = args[0].split(" ").map((n) => parseInt(n, 10));
  const N = array1[0];
  const V = array1[1];
  const A = args[1].split(" ").map((n) => parseInt(n, 10));

  const hasArray = A.find((num) => num === V) ? "Yes" : "No";
  console.log(hasArray);
}

main(require('fs').readFileSync('/dev/stdin', 'utf8'));

TypeScript

import * as fs from 'fs'
const input = fs.readFileSync("/dev/stdin", "utf8")
const [nv, alist] = input.split("\n")

const [n,v,..._] = nv.split(" ").map(Number)
const list = alist.split(" ").map(Number)

const hasArray = list.find((num) => num === v) ? "Yes" : "No";
console.log(hasArray);
  • 条件に一致する配列の要素が存在する場合、Yesを返しています。

Yui's answer

// 入力値を受け取る
function main(input) {
  const args = input.split("\n"); // 入力文字列を改行で分割し、新しい配列を作成
  const inputArray = args.map((n) => n.split(" ")); // さらに空白文字列で配列を分割
  const array1 = args[0].split(" ").map((n) => parseInt(n, 10));
  const N = array1[0];
  const V = array1[1];
  const A = args[1].split(" ").map((n) => parseInt(n, 10));

 
  // 配列の要素の中に整数Vが含まれるか判定
  if (A.find((element) => element === V)){
    console.log("Yes");
  } else {
    console.log("No");
  }
}

main(require('fs').readFileSync('/dev/stdin', 'utf8'));
  • readFileSyncメソッドは、同期的にファイルを読み込むfsモジュールのメソッドです。fs.readFileSync(path\[, options\])が基本形です。
  • fsモジュールは、Node.jsでファイルの読み書きを行うための基本的な関数を提供するモジュールです。

参考

アルゴ式 Beta JavaScript標準入力まとめ【パターン別】

2022年4月29日 りあクト! 第6章 特別なフォーマッタ 『Prettier』 (p.67~)

Prettier

Prettierはフロントエンドのメジャーどころをほぼ網羅しているフォーマッタです。 TypeScript、HTML、CSS、Vue、Angular、GraphQL、CSS in JS の styled-components など

コードフォーマッタとは

インデントや改行などの記述スタイルのフォーマットを統一して整形するツールを指します。

導入するメリット

開発者がコードの書き方のスタイルをめぐる論争をやめさせる目的で開発されているので、新人からベテランまで一律のコードに直してくれるところです。(無駄な言い争いがなくなります) 具体的には以下になります。

  • ソースコードの品質を保つため(コードのスタイルの一貫性を保つため)
  • コードレビュー時に、設計や命名などの重要な箇所に集中するため(コードのスタイルの指摘に時間を割くのを防ぐため)
  • 複数のメンバーが各自の整形ルールを適用し、更新する度に余計な差分が発生することを防ぐため
  • ソースコードを綺麗にするための労力(スタイル定義の議論や時間)を費やさなくて済むため
  • ツールに任せられることはツールに任せてしまった方が今後楽になるため

ESLintとPrettierを併用する理由

Prettier 入門 ~ESLintとの違いを理解して併用する~に、ESLintとPrettierを併用する理由が詳しく記載されているので、以下に引用します。

ESLint でもeslint --fixでコード整形ができるが、Prettier の方がコード整形が優れているから。

具体的には以下の点が優れている。

・ESLint では整形できないコードを整形できる
・ESLint と比べて手軽で確実に整形できる

但し、PrettierはESLintのような構文チェック機能がない

そのため、コードの整形は Prettier が行い、コードの構文チェックは ESLint が行うように併用する必要があります。

Prettierの環境を作る

パッケージの導入

ESLintの環境にPrettierを加えるには、以下の2つのパッケージを導入します。

  • prettier
    • Prettier本体
  • eslint-config-prettier
    • Prettierと競合する可能性のあるESLintの各種ルールを無効にする共有設定

パッケージをインストールしたら.eslintrc.jsのextendsオプションの最後に'prettier'を追加します。

.prettierrcでPrettierのオプションを設定

設定オプション一覧はドキュメントに記載があります。 https://prettier.io/docs/en/options.html

書籍では以下の3項目の設定を変更していました。

{
  "singleQuote": true,
  "trailingComma": "all",
  "endOfLine": "auto"
}

カスタマイズした設定以外はデフォルト値が適用されます。

ESlintで設定したルールとPrettierで設定したルールが衝突していないかをチェックする

$ npx exlint-config-prettier 'src/**/*.{js,jsx,ts,tsx}'
No rules that are unnecessary or conflist with Prettier were found.

上記は衝突していない場合に表示されます。

衝突した場合
The following rules are unnecessary or might conflict with Prettier:
- @typescript-eslint/indent

この場合は@typescript-eslint/indentの設定が不要なので .eslintrc.js から削除します。

Prettierがnpmのscriptsで実行されるようにpackage.jsonに登録する

"scripts": {
 ︙
 "eject": "react-scripts eject",
+ "fix": "npm run -s format && npm run -s lint:fix",
+                 " f o r m a t " : " p r e t t i e r - - w r i t e - - l o g l e v e l = w a r n
'{public,src}/**/*.{js,jsx,ts,tsx,html,gql,graphql,json}'",
    "lint": "eslint 'src/**/*.{js,jsx,ts,tsx}'",
    "lint:fix": "eslint --fix 'src/**/*.{js,jsx,ts,tsx}'",
+   "lint:conflict": "eslint --print-config .eslintrc.js | eslint-config-prettier-check",
     "preinstall": "typesync"
},

衝突ルールの検出もしています。

VSCodeの設定

settings.jsonに追記します。

"editor.defaultFormatter": "esbenp.prettier-vscode",
"[graphql]": {
  "editor.formatOnSave": true
},
"[javascript]": {
  "editor.formatOnSave": true
},
"[javascriptreact]": {
  "editor.formatOnSave": true
},
"[json]": {
  "editor.formatOnSave": true
},
"[typescript]": {
  "editor.formatOnSave": true
},
"[typescriptreact]": {
  "editor.formatOnSave": true
},

VSCodeのデフォルトのフォーマッタにPrettierを設定して各種言語の保存時に自動整形できるようにしています。

保存時に自動整形できるようになりました。

メモ

パスを通すとは

コマンド検索パス(コマンドサーチパス) を追加することです。

パスを通す理由

コマンド名と同じファイル名を持つ実行ファイルを探索できるようにするためです。パスを通すことで、実行ファイルのパスを入力しなくても、コマンドで実行ファイルを実行できます。

source

パスの内容をその場で反映させるためのコマンドです。

echo

画面にメッセージを表示させるためのコマンドです。 「echo $変数名」など環境変数やシェル変数を表示する際にも使用します。

参考

りあクト! TypeScriptで始めるつらくないReact開発 第3.1版【Ⅱ. React基礎編】 p.67~

Prettier 入門 ~ESLintとの違いを理解して併用する~

2022年4月28日 アルゴリズムを自作して問題を解く

問題

1以上の整数nが与えられたとき、1からnまでの整数の内 7で割り切れない数の合計を出力するプログラムを示してください。

例えばnが7の場合は1, 2, 3, 4, 6, 7の合計を出力する。

関数型プログラミングと手続型プログラミングの違い

関数型プログラミング

過程ではなく、結果に重きを置いている。何をしたいかを書くだけ

手続型プログラミング

結果を得るための過程に重きを置いている

関数型は過程をメソッドに入れて、過程を抽象化している

手続型で解く

手続き型の場合、以下のようになりました。

const testNum = (n) => {
  let totalNum = 0;
    for (let i = 0; i <= n ; i++) {
      i % 7 !== 0 ? totalNum += i : totalNum - 7;
    }
  return totalNum;
}
testNum(7)

▼出力結果 15

手続き型の場合、何をやっているのか読み解きづらいです。

関数型で解く

https://paiza.io/projects/L5DLuSgZAyNYZUADmjXsOg?language=ruby

const testNum = (n) => {
  const num = [...Array(n).keys()].map(i => ++i)
             .filter(n => n % 7 !== 0)
             .reduce((accumulator, currentValue) => {
               return accumulator + currentValue;
              }, 0);
  return num;
}

console.log(testNum(5));

▼出力結果 15

  • ...Array(n)では引数に渡された数字の数だけundefinedが要素として生成されます。
    • [undefined, undefined,undefined,undefined, undefined,undefined, undefined]
  • 配列.keys()でインデックス番号の数字の配列を生成します。
    • 7の場合[0, 1, 2, 3, 4, 5, 6]となります。
  • 配列を1から始めたいため、mapで要素に1をプラスしています。
    • [1, 2, 3, 4, 5, 6, 7]となります。
  • 7で割り切れる数を省きたいため、配列のfilterメソッドを使用します。
    • [1, 2, 3, 4, 5, 6]となります。
  • あとは配列内の数値を足すだけです。reduceメソッドを使用します。

[...Array(3).keys()]のコード例

// undefinedを要素とする配列を、生成する

const array = [...Array(3)];

console.log(array); // => [ undefined, undefined, undefined ]
// Array(3).keys()の結果をスプレッド構文で展開する

const array = [...Array(3).keys()];

console.log(array); // => [ 0, 1, 2 ]

TypeScriptで書く場合

コンソール

const testNum = (n: number): number => {
  const num = [...Array(n).keys()].map(i => ++i)
             .filter(n => n % 7 !== 0)
             .reduce((accumulator, currentValue) => {
               return accumulator + currentValue;
              }, 0);
  return num;
};

console.log(testNum(7));

エイリアスで書いた場合(呼び出しシグネチャ)

type TestNum = (n: number) => number

const testNum: TestNum = (n) => {
  const num = [...Array(n).keys()].map(i => ++i)
                                  .filter(n => n % 5 !== 0)
                                  .reduce((accumulator, currentValue) => {
                                    return accumulator + currentValue;
                                  }, 0);
  return num;
}

console.log(testNum(5));

2022年4月26日 りあクト! 第6章 ESLintの適用ルールをカスタマイズする (p.54~)

依存パッケージをリストアップする

npm info パッケージ名 peerDependenciesを実行すると、依存しているパッケージをリストアップできます。 以下の例では、styled-componentsの依存パッケージをリストアップしています。

➜  frontend git:(feature/add_#403) npm info styled-components peerDependencies

{
  react: '>= 16.8.0',
  'react-dom': '>= 16.8.0',
  'react-is': '>= 16.8.0'
}

.eslintrc.jsをカスタマイズ

module.exports = {
  env: {
    browser: true,
    es2021: true,
  },
  extends: [ // 
    'plugin:react/recommended', // ESLint の組み込みルールに対する公式推奨の共有設定 
    'airbnb', // 上のrecommendedと順番が前後すると意図しないところで TypeScript のコードに ESLint がエラーを指摘したりするようになる
    'airbnb/hooks',
    'plugin:import/errors',
    'plugin:import/warnings',
    'plugin:import/typescript',
    'plugin:@typescript-eslint/recommended',
    // eslint:recommended から TypeScript の一般的な文法とバッティングするルールを 調整するための共有設定
    'plugin:@typescript-eslint/recommended-requiring-type-checking',
  ],
  parser: '@typescript-eslint/parser',
  parserOptions: { // parserである@typescript-eslint/parser へ渡すオプションを定義します。
    ecmaFeatures: {
      jsx: true,
    },
    ecmaVersion: 12,
    project: './tsconfig.eslint.json', // 別ファイルを用意することでパーサが npm パッケージのファイルまでパースしてしまって、VS Code と連携させた際のパフォーマンスを落としたり、新規ファイルのパースの失敗を防ぎます。
    sourceType: 'module',
    tsconfigRootDir: __dirname,
  },
  plugins: [
    '@typescript-eslint',
    'import',
    'jsx-a11y',
    'react',
    'react-hooks',
  ],
  root: true,
  rules: {
    // occur error in `import React from 'react'` with react-scripts 4.0.1
    'no-use-before-define': 'off',
    '@typescript-eslint/no-use-before-define': [
      'error',
    ],
    'lines-between-class-members': [
      'error',
      'always',
      {
        exceptAfterSingleLine: true,
      },
    ],
    'no-void': [
      'error',
      {
        allowAsStatement: true,
      },
    ],
    'padding-line-between-statements': [
      'error',
      {
        blankLine: 'always',
        prev: '*',
        next: 'return',
      },
    ],
    '@typescript-eslint/no-unused-vars': [
      'error',
      {
        'vars': 'all',
        'args': 'after-used',
        'argsIgnorePattern': '_',
        'ignoreRestSiblings': false,
        'varsIgnorePattern': '_',
      },
    ],
    'import/extensions': [
      'error',
      'ignorePackages',
      {
        js: 'never',
        jsx: 'never',
        ts: 'never',
        tsx: 'never',
      },
    ],
    'react/jsx-filename-extension': [
      'error',
      {
        extensions: ['.jsx', '.tsx'],
      },
    ],
    'react/jsx-props-no-spreading': [
      'error',
      {
        html: 'enforce',
        custom: 'enforce',
        explicitSpread: 'ignore',
      },
    ],
    'react/react-in-jsx-scope': 'off',
  },
  overrides: [
    {
      'files': ['*.tsx'],
      'rules': {
        'react/prop-types': 'off',
      },
    },
  ],
  settings: {
    'import/resolver': {
      node: {
        paths: ['src'],
      },
    },
  },
};
  • extendsに各プラグインルールの推奨の共有設定が記述してあります。
  • ESLintプラグインはインストールしただけでは読み込まれないため、extendsに設定することで使用可能になります。
  • 共有設定の順番には意味があります。共有設定間で設定ルールの値が衝突した場合、後に記述されたものが先に記述されたものを上書きする仕様になっています。
  • 依存関係の順番がある場合はドキュメントに書かれているはずなのでプラグイン・拡張ルールセットをインストールするときは、チェックしましょう。

parserのオプションで指定したtsconfig.eslint.json

別ファイルを用意することでパーサが npm パッケージのファイルまでパースしてしまうことによる、VSCodeと連携時のパフォーマンスの低下や、新規ファイルのパースの失敗を防ぎます。

extends内のprojectの記述で別ファイルを読み込む設定が行われています。

 parser: '@typescript-eslint/parser',
  parserOptions: { // parserである@typescript-eslint/parser へ渡すオプションを定義します。
    ecmaFeatures: {
      jsx: true,
    },
    ecmaVersion: 12,
    project: './tsconfig.eslint.json', // 別ファイルを用意することでパーサが npm パッケージのファイルまでパースしてしまって、VS Code と連携させた際のパフォーマンスを落としたり、新規ファイルのパースの失敗を防ぎます。
    sourceType: 'module',
    tsconfigRootDir: __dirname,
  },

tsconfig.eslint.json

{
  "extends": "./tsconfig.json",
  "include": [
    "src/**/*.js",
    "src/**/*.jsx",
    "src/**/*.ts",
    "src/**/*.tsx"
  ],
  "exclude": [
    "node_modules"
  ]
}

pluginsの設定

plugins: [
    '@typescript-eslint',
    'import',
    'jsx-a11y',
    'react',
    'react-hooks',
  ],
  root: true,
  • 読み込ませる追加ルールのプラグインです。
  • インストールしただけでは使えず、上記のように設定する事で使用可能になります。
  • rootオプションは、ESlintはデフォルトの挙動では親ディレクトリの設定ファイルまで読み込んでしまいます。trueにする事で防ぐことができます。(個々のケースで変更するべき)

VS Code拡張機能でコーディング中にESLintが走るように設定する

拡張機能 : ESLint

https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint

メニューの Code > Preferences > Settings で開いたタブグループ右横のアイコン『Open Settings (JSON)』から設定ファイル settings.json を開いて次の内容を追加

"editor.codeActionsOnSave": {
  "source.fixAll.eslint": true
},
"editor.formatOnSave": false,
"eslint.packageManager": "yarn",
"typescript.enablePromptUseWorkspaceTsdk": true
  • ファイル保存時にESLintの自動整形が走るようにする設定です。
  • 最後の行はプロジェクトがTypeScriptを仕様している場合、VSCodeの内蔵のLintを使用するか、プロジェクトのLintを使用するかの設定です。

.eslintignoreファイル

lintチェック対象外となるファイルを定義できるファイルです。

build/
public/
**/converage/
**/node_modules/
**/*.min.js
*.config.js
.*lintrc.js

package.jsonでnpmのスクリプトを追加

後半の三行を追加します。

  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject",
    "lint": "eslint 'src/**/*.{js,jsx,ts,tsx}'",
    "lint:fix": "eslint --fix 'src/**/*.{js,jsx,ts,tsx}'",
    "preinstall": "typesync || :"
  },

typesyncとは

package.jsonを見て足りない型定義パッケージがあれば自動で追加してくれるパッケージです。

このプロジェクトではtypesyncがインストールされており、パッケージをインストールする際にpreinstallフックで自動的にtypesyncが走るように設定しています。

typesync || : スクリプト実行時にtypesyncがインストールされていない場合に何もしないようにすることでエラーを防いでいます。

ある種のスクリプト名は特別です。定義されている場合、preinstallスクリプトはパッケージがインストールされる前にyarnによって呼び出されます。互換性の理由から、install、postinstall、prepublish、prepareと呼ばれるスクリプトはすべて、パッケージのインストールが完了した後に呼び出されることになります。 スタートスクリプトの値のデフォルトは、node server.jsです。

  • yarn add {package} で任意のパッケージをインストール
  • yarn add コマンドの前に必ず実行される特別なスクリプト名のpreinstallにtypesyncを設定する事で、パッケージをインストールする事と同時に型定義ファイルもインストールできるようになります。
  • 初回のyarn installコマンド実行時にtypesyncはインストールされていない事で起こるエラーを防ぐために || : を付与しています。

参考

りあクト! TypeScriptで始めるつらくないReact開発 第3.1版【Ⅱ. React基礎編】 p.54~

ESlint公式ドキュメント Rules

2022年4月25日 りあクト! 第6章 Linter とフォーマッタでコード美人に (p.45~)

RubyではRubocopなどを用いることでコードのバグの警告や自動整形を行うことが出来ます。対してJavaScriptではlinterやコードフォーマッタを使用します。

linterとは

コードを静的解析してコンパイルではじかれない潜在的なバグを警告するものです。

放っておくと故障の原因となる糸くずを片っぱしから絡めとる乾燥機の『lint trap (糸くずフィルター)』に似ていることから 各種言語で書かれたコードを解析して構文チェックを行うことを 『lint』と動詞化して表現されるようになり、さらにそのプログラムは『linter』と呼ばれるようになったそうです。

コードフォーマッタとは

インデントや改行などのスタイルを一律に自動整形してくれるものです。

ESlint

開発者が独自のlintルールを作れるようにすること、という動機で創られたlinterです。 拡張性に加え、充実したドキュメント、JSHint よりも読みやすくかつ柔軟に記述できる設定ファイル、出力はメッセージとともに抵触したルール の ID が表示されてしっかり根拠が説明されるという親切設計から、ユーザー数を急激に伸びていきました。

2016年4月にJSCSという別のツールの機能を取り入れることでさらにシェアが拡大しました。

JSCS(JavaScript Code Style checker)

コードスタイルをチェックすることや、チェックに引っかかった箇所を強制的に修正するコードフォーマッタの機能を備えたツールです。

TSlint

2019年1月にMicrosoftのTypeScript開発チームがそれまで主力であったTSlintをあらゆる問題があることから見限り、ESlintのTypeScript対応プロジェクトを始動した事をきっかけに、TSlintの作者はTSlintプロジェクトを非推奨としてESlintへの段階的な移行をアナウンスしました。 現在ではESlintがダウンロード数でトップのlinterとなっています。

linterの存在

ツールの栄枯盛衰はありますが、JavaScriptやTypeScriptはlinterの存在があってはじめて言語として完成されます。
linterはモダンフロントエンド開発において必要不可欠なツールとして使用されています。

ESLint の適用ルールをカスタマイズする

Parser

ソースコードを特定の言語仕様に沿って解析してくれるライブラリ。 ESlintにはJavaScriptのパーサが組み込まれているが、標準ではTypeScriptには対応していないので、TypeScriptのパーサを導入する。

Plugin

ESLintの組み込みルール以外に独自のルールを追加するもの。 それらを適用した推奨の共有設定とパッケージングして提供されることが多い。

共有設定(Shareable Config)

複数のルールの適用をまとめて設定するもの。 ESlintに同梱されるeslint:recommendedやAirbnb社が提供しているeslint-config-airbnbが有名。

設定例 (.esluntrc)

module.exports = {
  env: { // プログラムの実行環境をESlintに伝える
    browser: true,
    es2021: true,
  },
  extends: [ // 複数のルールをまとめる共有設定のオプション。
    'plugin:react/recommended',
    'airbnb', 
    // ESLint に同梱される eslint:recommendedやAirbnb社が提供しているeslint-config-airbnbが有名
    // 共有設定間でルール設定が重複している場合、リストの後ろに記述されたほうが 優先される
    
  parser: '@typescript-eslint/parser', // ESLint が使用するパーサを指定する
  parserOptions: { // パーサの各種実行オプションを設定する
    ecmaFeatures: {
      jsx: true,
    },
    ecmaVersion: 12,
    sourceType: 'module',
  },
  plugins: [ // 任意のプラグインを組み込む
    'react',
    '@typescript-eslint',
  ],
  rules: { // 適用する個々のルールと、エラーレベルや例外などその設定値を記述する
  },
    // ルールは共有設定で読み込まれているため、個別で無効にしたり例外を設ける場合に適用する
};

設定ファイルのプロパティの意味

env

プログラムの実行環境をESlintに教える。個別の環境ごとにglobalsの値がプリセットされています。

extends

共有設定を適用する。共有設定はESlintに標準で含まれているものか別途インストールしたもの、またはインストール済みプラグインのパッケージに含まれているものを指定します。 なおここに記述した共有設定間でルール設定が重複している場合、リストの後ろに記述された方が優先されます。

parser

ESlintが使用するパーサを指定します。

parserOptions

パーサの各種実行オプションを指定します。

plugins

任意(インストール済み)のプラグインを組み込みます。

rules

適用する個々のルールと、エラーレベルや例外などの設定値を記述します。

参考

りあクト! TypeScriptで始めるつらくないReact開発 第3.1版【Ⅱ. React基礎編】 p.45~