Search code examples
typescripteslintvscode-extensions

How do I configure ESLint flat config with Typescript in VSCode? (without FlatCompat)


How do I:

  • transition to ESLint flat config
  • set up linting config for Typescript in the new format
  • get the ESLint extension working again in VSCode

Solution

  • I struggled with this for a couple of hours before figuring out a pretty clean solution. It doesn't rely on FlatCompat (which would keep legacy config alive) so thought I'd document it here for the benefit of others facing the same challenge:

    ESLint flat config is quite different from the previous format. It drove me nuts at first but it's actually a fair bit simpler once it clicks, To help understand the "flat config" the following pointers helped me:

    • Config is nothing more complicated than an array of objects. This is simpler than the previous format but might not be obvious at first.
    • Each object in the array can define whatever ESLint configuration it wants
    • Each object can target certain files by including or ignoring a set of files (useful because .eslintignore is no longer available)
    • Each file being linted will have all matching configurations applied - I believe in the order they appear in the array

    Setup for VSCode - at the time of writing you'll need:

    • ESlint plugin v3.0.5 or above (this currently requires "switch to pre-release version") in the plugin's installation page
    • Add "eslint.useFlatConfig": true to your settings.json (this was previously eslint.experimental.useFlatConfig)

    Install the following dependencies:

        yarn add --dev \
          eslint \
          @eslint/js \
          typescript-eslint \
          --
    

    Use the following eslint.config.js file to get you started (locate it alongside package.json). This provides defaults from https://typescript-eslint.io/getting-started/. This config additionally allows you to add ignored files, which is useful because .eslintignore is no longer available. NB the config is 'just Javascript' so you can make additional changes. This uses module.exports which avoids the need to add type: "module" to package.json:

        const eslint = require('@eslint/js');
        const tseslint = require('typescript-eslint');
    
        const ignores = [
          '**/*.js',
        ];
    
        module.exports = tseslint.config(
          {
            ...eslint.configs.recommended,
            ignores,
          },
          ...tseslint.configs.recommended.map((config) => ({
            ...config,
            ignores,
          })),
        );
    

    Pro:

    • Once I stopped cursing, I realised it's actually quite clean, even if it did eat up two hours of my life I wasn't prepared to budget to make the transition
    • The config above is a lot smaller than the sticky nest of stuff I had accumulated under the old config

    Con:

    • I was previously using AirBnB config but decided I needed to dump that because it's not (yet) available in flat config format
    • Applying a different set of linting rules meant a raft of (mostly simple) changes across my codebase

    I hope this saves you some time figuring out how to make the transition.