What is the best way to set up the parser and plugins using ESLint's updated flat configuration?

How can ESLint be configured using the new "flat config" system (specifically with the eslint.config.js file) to work seamlessly with both @typescript-eslint/eslint-plugin and /parser?

I have been struggling to make ESLint's new configuration system play well with plugins, and conversely, I am unable to get plugins to function smoothly with flat config.

When it comes to linting TypeScript code with ESLint, incorporating the two essential plugins listed below is crucial. These plugins define rules that enable ESLint to effectively lint TypeScript code bases:

My current configuration file resembles the example provided below. However, please note that this is just my latest attempt as I have experimented with various approaches:

import eslintPlugin from '@typescript-eslint/eslint-plugin'

export default [
  {
    files: ["src/**/*.ts", "src/main.cts", "src/main.mts"],
    ignores: ["**/*.d.*", "**/*.map.*", "**/*.js", "**/*.mjs", "**/*.cjs"],
    plugins: { eslintPlugin },

    languageOptions: {
      ecmaVersion: "latest",
      sourceType: "module",
      parser: "eslintPlugin/parser",
    },

    rules: {
      semi: "error",
      quotes: ["error", "single"],
      indent: [
        "error",
        2,
        {
          SwitchCase: 1,
          VariableDeclarator: "first",
          ImportDeclaration: "first",
          ArrayExpression: "first",
          ObjectExpression: "first",
          CallExpression: { arguments: "first" },
          FunctionDeclaration: { body: 1, parameters: 4 },
          FunctionExpression: { body: 1, parameters: 4 },
        },
      ],
    },
  },

];

In addition, I utilize the TypeScript ESLint Language Service plugin. I prefer not to have any overlap in error reporting between TypeScript and ESLint; therefore, I do not use any ESLint extension. Instead, I have integrated a build system that conducts linting on my project as I work, and any errors identified by ESLint are presented through the TSC compiler.

However, the issue persists – I am still encountering difficulties getting the language service plugin to cooperate with flat config.

Answer №1

In my setup with TypeScript and flat configuration, I have identified some key elements in the configuration:

import ts from '@typescript-eslint/eslint-plugin';
import tsParser from '@typescript-eslint/parser';
import functional from 'eslint-plugin-functional';
import imprt from 'eslint-plugin-import'; // 'import' is ambiguous & prettier has trouble

...

    languageOptions: {
      parser: tsParser,
      parserOptions: {
        ecmaFeatures: { modules: true },
        ecmaVersion: 'latest',
        project: './tsconfig.json',
      },
    },
    plugins: {
      functional,
      import: imprt,
      '@typescript-eslint': ts,
      ts,
    },

...

    rules: {
      ...ts.configs['eslint-recommended'].rules,
      ...ts.configs['recommended'].rules,

      'ts/return-await': 2,


It should be noted that the ts plugin appears twice in the configuration. The shared configurations use a longer namespace than the one intended for usage.

Answer №2

I've had success with this solution, but I still feel like the API could use some simplification.

const typescriptPlugin = require("@typescript-eslint/eslint-plugin");
const typescriptParser = require("@typescript-eslint/parser");

const tsOverrideConfig = typescriptPlugin.configs["eslint-recommended"].overrides[0];
const tsRecommemdedConfig = typescriptPlugin.configs.recommended;
const files = ["**/*.ts", "**/*.tsx"];

module.exports = [
  "eslint:recommended",
  {
    files,
    linterOptions: {
      reportUnusedDisableDirectives: true,
    },
    languageOptions: {
      parser: typescriptParser,
    },
    plugins: {
      "@typescript-eslint": typescriptPlugin,
    },
  },
  { files, rules: tsOverrideConfig.rules },
  { files, rules: tsRecommemdedConfig.rules },
];

Answer №3

Here's my custom flat configuration file eslint.config.mjs that includes the following key features:

  • Integration with Typescript parser and plugin
  • Support for Node.js and Mocha environments
  • Utilization of ESM format across projects, including CJS setups
import globals from "globals";
import tsParser from "@typescript-eslint/parser";
import tsPlugin from "@typescript-eslint/eslint-plugin";
import eslintJsPlugin from "@eslint/js";

export default [
  {
    rules: eslintJsPlugin.configs.recommended.rules,
  },
  {
    files: [ "**/*.ts" ],
    languageOptions: {
      parser: tsParser,
      globals: globals.node,
    },
    plugins: {
      "@typescript-eslint": tsPlugin,
    },
    rules: {
      ...tsPlugin.configs.recommended.rules,
      "no-console": "error",
    }
  },
  {
    files: [ "test/**/*.ts" ],
    languageOptions: {
      globals: globals.mocha,
    },
  },
];

To execute eslint using this configuration in a CommonJS project, I rely on the specified command:

ESLINT_USE_FLAT_CONFIG=true npx eslint src test

Answer №4

Take a look at the flatConfig example available in the microsoft/vscode-eslint repository (➜ VSCode ESLint extension).

For instance: eslint.config.js

const globals = require('globals');
const typescriptParser =  require('@typescript-eslint/parser');
const typescriptPlugin = require('@typescript-eslint/eslint-plugin');

module.exports = [
    "eslint:recommended",
    {
        files: ["**/*.js"],
        languageOptions: {
            parserOptions: {
                sourceType: "module"
            },
            globals: {
                ...globals.browser,
                ...globals.node,
                ...globals.es6,
                ...globals.commonjs
            }
        },
    },
    {
        files: ["sub/*.js"],
        rules: {
            "no-undef": "warn",
            "no-console": "warn"
        }
    },
    {
        files: ["*.ts", "**/*.ts"],
        plugins: {
            "@typescript-eslint": typescriptPlugin
        },
        languageOptions: {
            parser: typescriptParser,
            parserOptions: {
                project: "./tsconfig.json",
                sourceType: "module",
                ecmaVersion: 2020
            }
        },
        rules: {
            "semi": "off",
            "@typescript-eslint/semi": "error",
            "no-extra-semi": "warn",
            "curly": "warn",
            "quotes": ["error", "single", { "allowTemplateLiterals": true } ],
            "eqeqeq": "error",
            "indent": "off",
            "@typescript-eslint/indent": ["warn", "tab", { "SwitchCase": 1 } ],
            "@typescript-eslint/no-floating-promises": "error"
        }
    }
]
Discover more about ESLint's new config system with these blog posts (flat config):
  1. ESLint's new config system, Part 1: Background
  2. ESLint's new config system, Part 2: Introduction to flat config (particularly interesting)
  3. ESLint's new config system, Part 3: Developer preview

Answer №5

It is worth noting that typescript-eslint proposes an alternative approach for defining their eslint Flat Config:

For example: eslint.config.js

// @ts-check

import eslint from '@eslint/js';
import tseslint from 'typescript-eslint';

export default tseslint.config(
  eslint.configs.recommended,
  ...tseslint.configs.recommended,
);

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

A custom function that changes the state of a nested object using a specified variable as the key argument

My goal is to update the state of an object using a function called updateDatas. This function takes the arguments key, possibly subKey, and value. interface Datas { code: number; item1: Item; } interface Item { id: number; name: string; } const ...

Unable to find the module... designated for one of my packages

Within my codebase, I am utilizing a specific NPM package called my-dependency-package, which contains the module lib/utils/list-utils. Moreover, I have another package named my-package that relies on my-dependency-package. When attempting to build the pr ...

What could be the reason for the absence of a TypeScript error in this situation?

Why is it that the code below (inside an arbitrary Class) does not show a TypeScript error in VSCode as expected? protected someMethod (someArg?: boolean) { this.doSomething(someArg) } protected doSomething (mustBePassedBoolean: boolean) { /* ... * ...

Troubleshooting Angular 2 Fallback Route Failure

My current project is using Angular 2 Webpack Starter but I am having trouble with the fallback route. In my app.routes.ts file, I have defined the routes as follows: import { Routes } from '@angular/router'; import { HomeComponent } from &apos ...

Ways to access a nested property within an array

I'm having an issue when trying to access a sub property of an array. Here's the snippet in question: ngOnInit() { this.menus = this.navService.defaultMenu; console.log(this.getMenusItem()); this.registerChangeInProjects(); } T ...

Modify the ShortDate formatting from "2020/06/01" to "2020-06-01"

I am looking to modify the shortDate format in my template file. Currently, when I try to change it to use "-", it still displays the date with "/". What I actually want is for the output to be formatted as yyyy-MM-dd. <ngx-datatable-column name="C ...

Leveraging the power of NestJS in conjunction with Apollo Server version 2

I recently delved into learning nestjs and decided to give this graphql example a try. The issue I encountered is that the example was originally designed for apollo-server version 1, and I'm having difficulty adapting it to work with apollo-server v ...

Leverage the power of TypeScript custom transformer and project reference for enhanced

I am currently working on a project that involves using both project references and custom transformers. The issue I am facing is that project references require the use of TSC for incremental compilation, but when TSC is used, the transformers are not app ...

Using a function from one class within another class by passing it as a prop

Below are the methods found in my Search.tsx class. renderSuggestion(suggestion) { <div className="buttons"> <button className="button">View Location</button> <button className="button whitebutton" onClick={this.h ...

Transform nested properties of an object into a new data type

I created a versatile function that recursively converts nested property values into numbers: type CastToNumber<T> = T extends string ? number : { [K in keyof T]: CastToNumber<T[K]> }; type StringMap = { [key: string]: any }; const castOb ...

Failed deployment of a Node.js and Express app with TypeScript on Vercel due to errors

I'm having trouble deploying a Nodejs, Express.js with Typescript app on Vercel. Every time I try, I get an error message saying "404: NOT_FOUND". My index.ts file is located inside my src folder. Can anyone guide me on the correct way to deploy this? ...

A versatile method to organize a multi-dimensional array of items

I need help sorting a nested array using a generic function. The sorting should be based on the values of the items within the nested array. Here is an example of my array: type Person = { id: number, name: string, childs: Child[] } type Chil ...

Angular 10 Reactive Form - Controlling character limit in user input field

I'm currently developing an Angular 10 reactive form and I am looking for a way to restrict the maximum number of characters that a user can input into a specific field. Using the maxLength Validator doesn't prevent users from entering more chara ...

Creating an enum from an associative array for restructuring conditions

Hey everyone, I have a situation where my current condition is working fine, but now I need to convert it into an enum. Unfortunately, the enum doesn't seem to work with my existing condition as mentioned by the team lead. Currently, my condition loo ...

Substitute all instances of null bytes

I need to remove null bytes from a string. However, after replacing the null bytes \u0000 in the string let data = {"tet":HelloWorld.\u0000\u0000\u0000\u0000"} let test = JSON.parse(data).tet.replace("\u0000", ""); I always ...

Creating a dynamic return statement in typescript: A step-by-step guide

I am looking to dynamically set a return value to a variable based on values retrieved from an API. The current function in question uses static values: this.markDisabled = (date: NgbDate) => { return (this.calendar.getWeekday(date) !== 5 && ...

Error occurred after attempting to make a GET request

What I aim to achieve: I need to send two parameters from the front-end to the back-end. This is the code snippet: In TypeScript file: activeFromActiveToQuery(req?: any): Observable<ResponseWrapper>{ const options = createRequestOption(req) ...

Tests in headless mode with Cypress may fail sporadically, but consistently pass when running in a real browser

Currently, I am utilizing Cypress 9.5 to conduct tests on an Angular 13 application with a local PHP server as the backend. Throughout the testing process, I have encountered successful results when running the tests in the browser multiple times. However ...

What steps can I take to resolve the issue of the Error value not being iterable?

I encountered an issue in my table where I get the error message value is not iterable when there is no value to iterate through. How can I handle this error in my code? Snippet of Code: if (null != data && data) { data = data.map((item) => ...

How can I subtract a value from my array in Angular?

I've been troubleshooting this problem for a while now and I'm hoping that someone here can assist me with finding a solution. The issue at hand involves an array object containing various values such as id, title, amountCounter. Specifically, t ...