Skip to content

Bug: config-helper.ts has unexpected behavior when base config contains only meta keys #10754

Closed
@jeremy-code

Description

@jeremy-code

Before You File a Bug Report Please Confirm You Have Done The Following...

  • I have tried restarting my IDE and the issue persists.
  • I have updated to the latest version of the packages.
  • I have searched for related issues and found none that matched my issue.
  • I have read the FAQ and my problem is not listed.

Relevant Package

typescript-eslint

There are two bugs related to this issue: one meaningful and one mostly inconsequential.


1. Using extends in tseslint.config() creates global ignores

Playground Link

Reproduction with StackBlitz.

ESLint Config

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

export default tseslint.config(
  eslint.configs.recommended,
  tseslint.configs.recommended,
  {
    extends: [tseslint.configs.disableTypeChecked],
    ignores: ['**/*.ts', '**/*.tsx'],
  }
);

Expected Result

I expect that the ignores key only apply to the extend config, or at the very least not create a global ignores that affects the entire ESLint config.

In other words, I expect the resulting configuration array to be equivalent to this:

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

export default [
  eslint.configs.recommended,
  ...tseslint.configs.recommended,
  {
    ignores: ['**/*.ts', '**/*.tsx'],
    ...tseslint.configs.disableTypeChecked,
  }
];

Actual Result

If you look into the config inspector, the resulting config is the following:

> ...eslint/defaults
> eslint.configs.recommended
> ...tseslint.configs.recommended
> typescript-eslint/disable-type-checked
  - Ignore: ["**/*.ts", "**.tsx"]
  - ...tseslint.configs.disable-type-checked
> anonymous #10
  - Ignore files globally: ["**/**.ts", "**/*.tsx"]

In other words, the equivalent config array is

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

export default [
  eslint.configs.recommended,
  ...tseslint.configs.recommended,
  {
    ignores: ['**/*.ts', '**/*.tsx'],
    ...tseslint.configs.disableTypeChecked,
  },
  // Global ignores, ignores all .ts and .tsx files
  { ignores: ['**/*.ts', '**/*.tsx'] },
];

Extends will create a configuration with only the ignores key, which is parsed as a global ignores. Then, .ts and .tsx will not be linted.

This can be seen in the reproduction where src/index.ts is not linted as-is, while removing the extends config correctly allows it to be linted.


2. Using extends in tseslint.config() creates extraneous config

Playground Link

Reproduction with StackBlitz

ESLint Config

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

export default tseslint.config(
  eslint.configs.recommended,
  tseslint.configs.recommended,
  {
    extends: [tseslint.configs.disableTypeChecked],
    files: ['file'],
    ignores: ['ignored'],
    name: 'my-config',
  }
);

Expected Result

Per ESLint’s documentation (Debug your Configuration#Print a File’s Calculated Configuration), "You won’t see any entries for files, ignores, or name, because those are only used in calculating the final configuration and so do not appear in the result[ing configuration]."

I expect that if there are no meaningful keys for configuration and I only want to extend those configs with those keys, it should not create an unnecessary configuration file, and only updates the configs accordingly.

The ESLint configuration array should look like:

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

export default [
  eslint.configs.recommended,
  ...tseslint.configs.recommended,
  {
    files: ['file'],
    ignores: ['ignored'],
    name: 'my-config',
    ...tseslint.configs.disableTypeChecked,
  }
];

Actual Result

If you look into the config inspector, the resulting config is the following:

> ...eslint/defaults
> eslint.configs.recommended
> ...tseslint.configs.recommended
> my-config_typescript-eslint/disable-type-checked
  - Applies to files matching: ["file"]
  - Ignore: ["ignored"]
  - ...tseslint.configs.disable-type-checked
> my-config
  - Applies to files matching: ["file"]
  - Ignore: ["ignored"]

Or equivalently

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

export default [
  eslint.configs.recommended,
  ...tseslint.configs.recommended,
  {
    name: "my-config_typescript-eslint/disable-type-checked",
    files: ["file"],
    ignore: ["ignored"],
    ...tseslint.configs.disableTypeChecked,
  },
  // This config doesn't do anything
  { 
    name: "my-config",
    files: ["file"],
    ignore: ["ignored"],
  },
];

The final config in the config array named my-config doesn't do anything and is unnecessary, and may make debugging harder in more complex ESLint configs.


Versions

package version
@typescript-eslint 8.22.0
TypeScript 5.7.3
ESLint 9.19.0

Metadata

Metadata

Assignees

No one assigned

    Labels

    accepting prsGo ahead, send a pull request that resolves this issuebugSomething isn't workinglocked due to agePlease open a new issue if you'd like to say more. See https://typescript-eslint.io/contributing.package: typescript-eslintIssues related to the typescript-eslint package

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions