Open6

Vue3 + TypeScript用ESLintルールを整理する

GANGANGANGAN

本件の内容を記事にしました。こちらも合わせてご確認ください。

https://zenn.dev/gangannikki/articles/organize-eslint-rules-for-vue3-typescript

以下スクラップではNext.js + TypeScriptのルールを調査・整理している。

こちらではVue3 + TypeScriptのルールを整理する。最終的には以下GitHubにまとめていく。

GANGANGANGAN

Vue.js 情報整理

Document

Usage

基本的にこれ見ればええ。

Vue3の場合は.eslintrc.jsに以下を設定すれば良い。

// .eslintrc.js
module.exports = {
  extends: [
    ...,
    'plugin:vue/vue3-recommended',
    ...,
  ]
}

整理内容まとめ

  • Vue3を利用する場合はvue/vue3-recommended、Vue2を利用する場合はvue/recommendedを利用すれば良い。公式ドキュメントに従えばよい。
  • vue3-recommendedでeslint:recommendedplugin:@typescript-eslint/recommendedprettierは設定されていない。必要に応じて追加必須であることがわかる。

各種ルールの内容整理

baseの中身は以下の通り。envなどは既に設定済み。

// eslint-plugin-vue/lib/configs/base.js
module.exports = {
  parser: require.resolve('vue-eslint-parser'),
  parserOptions: {
    ecmaVersion: 2020,
    sourceType: 'module'
  },
  env: {
    browser: true,
    es6: true
  },
  plugins: ['vue'],
  rules: {
    'vue/comment-directive': 'error',
    'vue/jsx-uses-vars': 'error'
  }
}

eslint-plugin-vueで対応していないVue3 Breaking Changesはどう吸収するか

GANGANGANGAN

TypeScript 情報整理

Document

Usage

// .eslintrc.js
module.exports = {
  extends: [
    'eslint:recommended',
    'plugin:@typescript-eslint/recommended',
    //  型情報によるLintチェックを行う場合
    'plugin:@typescript-eslint/recommended-requiring-type-checking',
    ...,
  ],
  // NOTE: parser, plugins はconfis/base.tsで設定済みのため追加しない
  parserOptions: {
    project: './tsconfig.eslint.json',
  },
}

情報整理まとめ

各種ルールの内容整理

公式としては以下の3つを推奨している。

Most projects should extend from at least one of:

  • recommended: Recommended rules for code correctness that you can drop in without additional configuration.
  • recommended-requiring-type-checking: Additional recommended rules that require type information.
  • strict: Additional strict rules that can also catch bugs but are more opinionated than recommended rules.

以下2つをextendsしている

configs/base.ts
// configs/base.ts
export = {
  parser: '@typescript-eslint/parser',
  parserOptions: { sourceType: 'module' },
  plugins: ['@typescript-eslint'],
};
configs/eslint-recommended.ts
// configs/eslint-recommended.ts
export = {
  overrides: [
    {
      files: ['*.ts', '*.tsx', '*.mts', '*.cts'],
      rules: {
        'constructor-super': 'off', // ts(2335) & ts(2377)
        'getter-return': 'off', // ts(2378)
        'no-const-assign': 'off', // ts(2588)
        'no-dupe-args': 'off', // ts(2300)
        'no-dupe-class-members': 'off', // ts(2393) & ts(2300)
        'no-dupe-keys': 'off', // ts(1117)
        'no-func-assign': 'off', // ts(2539)
        'no-import-assign': 'off', // ts(2539) & ts(2540)
        'no-new-symbol': 'off', // ts(7009)
        'no-obj-calls': 'off', // ts(2349)
        'no-redeclare': 'off', // ts(2451)
        'no-setter-return': 'off', // ts(2408)
        'no-this-before-super': 'off', // ts(2376)
        'no-undef': 'off', // ts(2304)
        'no-unreachable': 'off', // ts(7027)
        'no-unsafe-negation': 'off', // ts(2365) & ts(2360) & ts(2358)
        'no-var': 'error', // ts transpiles let/const to var, so no need for vars any more
        'prefer-const': 'error', // ts provides better types with const
        'prefer-rest-params': 'error', // ts provides better types with rest args over arguments
        'prefer-spread': 'error', // ts transpiles spread to apply, so no need for manual apply
        'valid-typeof': 'off', // ts(2367)
      },
    },
  ],
};

eslint-recommendedをextendsしているからplugin:@typescript-eslint/eslint-recommendedの追加extendsは不要。

マージしたrecommended
export = {
  // configs/base.ts
  parser: '@typescript-eslint/parser',
  parserOptions: { sourceType: 'module' },
  plugins: ['@typescript-eslint'],
  // configs/eslint-recommended.ts
  overrides: [
    {
      files: ['*.ts', '*.tsx', '*.mts', '*.cts'],
      rules: {
        'constructor-super': 'off', // ts(2335) & ts(2377)
        'getter-return': 'off', // ts(2378)
        'no-const-assign': 'off', // ts(2588)
        'no-dupe-args': 'off', // ts(2300)
        'no-dupe-class-members': 'off', // ts(2393) & ts(2300)
        'no-dupe-keys': 'off', // ts(1117)
        'no-func-assign': 'off', // ts(2539)
        'no-import-assign': 'off', // ts(2539) & ts(2540)
        'no-new-symbol': 'off', // ts(7009)
        'no-obj-calls': 'off', // ts(2349)
        'no-redeclare': 'off', // ts(2451)
        'no-setter-return': 'off', // ts(2408)
        'no-this-before-super': 'off', // ts(2376)
        'no-undef': 'off', // ts(2304)
        'no-unreachable': 'off', // ts(7027)
        'no-unsafe-negation': 'off', // ts(2365) & ts(2360) & ts(2358)
        'no-var': 'error', // ts transpiles let/const to var, so no need for vars any more
        'prefer-const': 'error', // ts provides better types with const
        'prefer-rest-params': 'error', // ts provides better types with rest args over arguments
        'prefer-spread': 'error', // ts transpiles spread to apply, so no need for manual apply
        'valid-typeof': 'off', // ts(2367)
      },
    },
  ],
  // configs/recommended.ts
  rules: {
    '@typescript-eslint/adjacent-overload-signatures': 'error',
    '@typescript-eslint/ban-ts-comment': 'error',
    '@typescript-eslint/ban-types': 'error',
    'no-array-constructor': 'off',
    '@typescript-eslint/no-array-constructor': 'error',
    'no-empty-function': 'off',
    '@typescript-eslint/no-empty-function': 'error',
    '@typescript-eslint/no-empty-interface': 'error',
    '@typescript-eslint/no-explicit-any': 'warn',
    '@typescript-eslint/no-extra-non-null-assertion': 'error',
    'no-extra-semi': 'off',
    '@typescript-eslint/no-extra-semi': 'error',
    '@typescript-eslint/no-inferrable-types': 'error',
    'no-loss-of-precision': 'off',
    '@typescript-eslint/no-loss-of-precision': 'error',
    '@typescript-eslint/no-misused-new': 'error',
    '@typescript-eslint/no-namespace': 'error',
    '@typescript-eslint/no-non-null-asserted-optional-chain': 'error',
    '@typescript-eslint/no-non-null-assertion': 'warn',
    '@typescript-eslint/no-this-alias': 'error',
    '@typescript-eslint/no-unnecessary-type-constraint': 'error',
    'no-unused-vars': 'off',
    '@typescript-eslint/no-unused-vars': 'warn',
    '@typescript-eslint/no-var-requires': 'error',
    '@typescript-eslint/prefer-as-const': 'error',
    '@typescript-eslint/prefer-namespace-keyword': 'error',
    '@typescript-eslint/triple-slash-reference': 'error',
  },
};

eslint-recommendedはどんなルール?

公式ドキュメントから引用: 引用元

This ruleset is meant to be used after extending eslint:recommended. It disables core ESLint rules that are already checked by the TypeScript compiler. Additionally, it enables rules that promote using the more modern constructs TypeScript allows for.

{
 "extends": [
   "eslint:recommended",
   "plugin:@typescript-eslint/eslint-recommended"
 ]
}

TypeScriptコンパイラでチェックされているESLintルールを無効化するESLintルール。3つの推奨ルールを利用する場合はextends済みの内容である。

GANGANGANGAN

Draft: Vuetify 情報整理

※ Vuetify3で調査

Document

Draft: Scoped CSS 情報整理

メンテナーに感謝しかないですね🙏

Document