diff --git a/docs/getting-started/Quickstart.mdx b/docs/getting-started/Quickstart.mdx
index 232fe15966d5..c362a5978ffd 100644
--- a/docs/getting-started/Quickstart.mdx
+++ b/docs/getting-started/Quickstart.mdx
@@ -35,9 +35,10 @@ Next, create an `eslint.config.mjs` config file in the root of your project, and
// @ts-check
import eslint from '@eslint/js';
+import { defineConfig } from 'eslint/config';
import tseslint from 'typescript-eslint';
-export default tseslint.config(
+export default defineConfig(
eslint.configs.recommended,
tseslint.configs.recommended,
);
@@ -47,21 +48,10 @@ This code will enable our [recommended configuration](../users/Shared_Configurat
#### Details
-- `tseslint.config(...)` is an **_optional_** helper function — see [`typescript-eslint`'s `config(...)`](../packages/TypeScript_ESLint.mdx#config).
+- `defineConfig(...)` is an optional helper function built in to current versions of ESLint. See [the ESLint configuration docs](https://eslint.org/docs/latest/use/configure/configuration-files) for more detail.
- `'@eslint/js'` / `eslint.configs.recommended` turns on [eslint's recommended config](https://www.npmjs.com/package/@eslint/js).
- `tseslint.configs.recommended` turns on [our recommended config](../users/Shared_Configurations.mdx#recommended).
-
-Aside on ESLint's `defineConfig()`
-
-ESLint also provides a `defineConfig()` helper similar to `tseslint.config()`.
-However, there is a types incompatibility issue that causes type errors to incorrectly be reported when mixing typescript-eslint's configs and `defineConfig()`.
-For now we recommend using `tseslint.config()` for use with typescript-eslint's configs.
-
-See [typescript-eslint#10899](https://github.com/typescript-eslint/typescript-eslint/issues/10899) for more details.
-
-
-
Aside on file extensions
@@ -111,7 +101,7 @@ We recommend you consider enabling the following two configs:
- [`stylistic`](../users/Shared_Configurations.mdx#stylistic): additional rules that enforce consistent styling without significantly catching bugs or changing logic.
```js title="eslint.config.mjs"
-export default tseslint.config(
+export default defineConfig(
eslint.configs.recommended,
// Remove this line
tseslint.configs.recommended,
diff --git a/docs/getting-started/Typed_Linting.mdx b/docs/getting-started/Typed_Linting.mdx
index 95f225038dd3..bc36f5589735 100644
--- a/docs/getting-started/Typed_Linting.mdx
+++ b/docs/getting-started/Typed_Linting.mdx
@@ -20,9 +20,10 @@ To enable typed linting, there are two small changes you need to make to your co
```js title="eslint.config.mjs"
import eslint from '@eslint/js';
+import { defineConfig } from 'eslint/config';
import tseslint from 'typescript-eslint';
-export default tseslint.config(
+export default defineConfig(
eslint.configs.recommended,
// Remove this line
tseslint.configs.recommended,
@@ -99,7 +100,7 @@ If you enabled the [`strict` shared config](../users/Shared_Configurations.mdx#s
```js title="eslint.config.mjs"
-export default tseslint.config(
+export default defineConfig(
eslint.configs.recommended,
// Removed lines start
tseslint.configs.strict,
diff --git a/docs/packages/TypeScript_ESLint.mdx b/docs/packages/TypeScript_ESLint.mdx
index 9fc886d872bd..e2c283adf146 100644
--- a/docs/packages/TypeScript_ESLint.mdx
+++ b/docs/packages/TypeScript_ESLint.mdx
@@ -16,12 +16,12 @@ This package is the main entrypoint that you can use to consume our tooling with
This package exports the following:
-| Name | Description |
-| --------- | -------------------------------------------------------------------------------------- |
-| `config` | A utility function for creating type-safe flat configs -- see [`config(...)`](#config) |
-| `configs` | [Shared ESLint (flat) configs](../users/Shared_Configurations.mdx) |
-| `parser` | A re-export of [`@typescript-eslint/parser`](./Parser.mdx) |
-| `plugin` | A re-export of [`@typescript-eslint/eslint-plugin`](./ESLint_Plugin.mdx) |
+| Name | Description |
+| --------------------- | ------------------------------------------------------------------------------------------------- |
+| `config` (deprecated) | A utility function for creating type-safe flat configs -- see [`config(...)`](#config-deprecated) |
+| `configs` | [Shared ESLint (flat) configs](../users/Shared_Configurations.mdx) |
+| `parser` | A re-export of [`@typescript-eslint/parser`](./Parser.mdx) |
+| `plugin` | A re-export of [`@typescript-eslint/eslint-plugin`](./ESLint_Plugin.mdx) |
## Installation
@@ -31,15 +31,16 @@ npm i typescript-eslint
## Usage
-We recommend getting started by using the `tseslint.config()` helper function in your ESLint config:
+We recommend getting started by using the default ESLint setup with our shared configs.
```js title="eslint.config.mjs"
// @ts-check
import eslint from '@eslint/js';
+import { defineConfig } from 'eslint/config';
import tseslint from 'typescript-eslint';
-export default tseslint.config(
+export default defineConfig(
eslint.configs.recommended,
tseslint.configs.recommended,
);
@@ -47,16 +48,16 @@ export default tseslint.config(
This config file exports a flat config that enables both the [core ESLint recommended config](https://www.npmjs.com/package/@eslint/js) and [our recommended config](../users/Shared_Configurations.mdx#recommended).
-:::note
-ESLint also provides a `defineConfig()` helper similar to `tseslint.config()`.
-However, there is a types incompatibility issue that causes type errors to incorrectly be reported when mixing typescript-eslint's configs and `defineConfig()`.
-For now we recommend using `tseslint.config()` for use with typescript-eslint configs.
+### `config(...)` (deprecated)
-See [typescript-eslint#10899](https://github.com/typescript-eslint/typescript-eslint/issues/10899) for more details.
+:::danger
-:::
+The `config(...)` utility function was deprecated in favor of ESLint core's [`defineConfig(...)`]() in [#10935](https://github.com/typescript-eslint/typescript-eslint/issues/10935).
+See [the `defineConfig` migration guide later](#migrating-to-defineconfig) for more details.
+
+The documentation here is preserved for historical reference and migration purposes.
-### `config(...)`
+:::
`tseslint.config(...)` takes in any number of ESLint config objects, each of which may additionally include an `extends` array of configs to extend.
`tseslint.config(...)` returns the equivalent ESLint config of applying the rest of the settings for each extension.
@@ -114,7 +115,7 @@ Otherwise it _will not_ impact your ability to use our tooling.
#### Flat config `extends`
-The `tseslint.config()` utility function also adds handling for the `extends` property on flat config objects.
+The `tseslint.config(...)` utility function also adds handling for the `extends` property on flat config objects.
This allows you to more easily extend shared configs for specific file patterns whilst also overriding rules/options provided by those configs:
```js
@@ -168,6 +169,79 @@ export default tseslint.config({
});
```
+#### Migrating to `defineConfig(...)`
+
+The core `defineConfig(...)` helper is a nearly exact clone of `tseslint.config(...)` that was [first released in ESLint v9.22.0](https://eslint.org/blog/2025/03/eslint-v9.22.0-released/).
+See [the ESLint blog post](https://eslint.org/blog/2025/03/flat-config-extends-define-config-global-ignores/#support-for-older-eslint-versions) for info on how to use `defineConfig(...)` with older versions of ESLint.
+
+At the time of writing there are a small number of known edge cases in which the two have different functionality.
+
+{/* https://github.com/prettier/prettier/issues/17816 -- prettier has trouble with the code fences in the custom elements */}
+
+{/* prettier-ignore */}
+1. Overriding `files` in `extends`.
+ When `files` is provided in both a base object and an extension, `tseslint.config(...)` _overrides_ the `files` property in the extension, whereas `defineConfig(...)` semantically intersects the two provided `files` specifiers.
+
+
+
+ ```ts title="eslint.config.mjs"
+ import tseslint from 'typescript-eslint';
+
+ export default tseslint.config({
+ files: ['a.ts'],
+ extends: [
+ {
+ files: ['b.ts'],
+ rules: {
+ 'some-rule': 'error',
+ },
+ },
+ ],
+ });
+
+ // is equivalent to
+
+ export default {
+ files: ['a.ts'],
+ rules: { 'some-rule': 'error' },
+ };
+ ```
+
+
+
+
+ ```ts title="eslint.config.mjs"
+ import { defineConfig } from 'eslint/config';
+
+ export default defineConfig({
+ files: ['a.ts'],
+ extends: [
+ {
+ files: ['b.ts'],
+ rules: {
+ 'some-rule': 'error',
+ },
+ },
+ ],
+ });
+
+ // is equivalent to
+
+ // The base config technically ensures that 'a.ts' is still included in
+ // the lint run, but otherwise the config has no effect, due to the
+ // intersection of 'a.ts' and 'b.ts' being empty.
+ export default {
+ files: ['a.ts'],
+ };
+ ```
+
+
+
+
+2. Type declarations (only applies to users who typecheck their eslint configs).
+ There are slight differences in the way types are declared between the two functions, which may cause typechecking errors when you switch from `tseslint.config(...)` to `defineConfig(...)` in some cases (see [#10899](https://github.com/typescript-eslint/typescript-eslint/issues/10899) for an example that used to impact typescript-eslint's own configs).
+ Type errors such as these do not indicate a runtime problem and can safely be ignored.
+
### Manual usage
[typescript-eslint's recommended and stylistic configurations](../users/configs) specify typescript-eslint `parser` and `plugin` options for you, so there is no need to manually provide those.
@@ -181,10 +255,11 @@ You can declare our plugin and parser in your config via this package, for examp
// @ts-check
import eslint from '@eslint/js';
+import { defineConfig } from 'eslint/config';
import jestPlugin from 'eslint-plugin-jest';
import tseslint from 'typescript-eslint';
-export default tseslint.config({
+export default defineConfig({
plugins: {
// highlight-next-line
'@typescript-eslint': tseslint.plugin,
@@ -226,10 +301,11 @@ This config:
// @ts-check
import eslint from '@eslint/js';
+import { defineConfig } from 'eslint/config';
import jestPlugin from 'eslint-plugin-jest';
import tseslint from 'typescript-eslint';
-export default tseslint.config(
+export default defineConfig(
{
// config with just ignores is the replacement for `.eslintignore`
ignores: ['**/build/**', '**/dist/**', 'src/some/file/to/ignore.ts'],
diff --git a/docs/troubleshooting/faqs/ESLint.mdx b/docs/troubleshooting/faqs/ESLint.mdx
index d1a5cdf0d809..a07e16a2f798 100644
--- a/docs/troubleshooting/faqs/ESLint.mdx
+++ b/docs/troubleshooting/faqs/ESLint.mdx
@@ -49,9 +49,9 @@ Note, that for a mixed project including JavaScript and TypeScript, the `no-unde
```js title="eslint.config.mjs"
-import tseslint from 'typescript-eslint';
+import { defineConfig } from 'eslint/config';
-export default tseslint.config(
+export default defineConfig(
// ... the rest of your config ...
{
files: ['**/*.{ts,tsx,mts,cts}'],
diff --git a/docs/troubleshooting/faqs/Frameworks.mdx b/docs/troubleshooting/faqs/Frameworks.mdx
index fc0e559b56fa..f80be6a84296 100644
--- a/docs/troubleshooting/faqs/Frameworks.mdx
+++ b/docs/troubleshooting/faqs/Frameworks.mdx
@@ -19,7 +19,7 @@ See [Changes to `extraFileExtensions` with `projectService`](../typed-linting/Pe
```js title="eslint.config.mjs"
-export default tseslint.config(
+export default defineConfig(
// ... the rest of your config ...
{
languageOptions: {
@@ -61,10 +61,11 @@ If you are running into issues parsing .vue files, it might be because parsers l
```js title="eslint.config.mjs"
import tseslint from 'typescript-eslint';
+import { defineConfig } from 'eslint/config';
// Add this line
import vueParser from 'vue-eslint-parser';
-export default tseslint.config(
+export default defineConfig(
// ... the rest of your config ...
{
languageOptions: {
diff --git a/docs/troubleshooting/faqs/General.mdx b/docs/troubleshooting/faqs/General.mdx
index 53b752ab9b80..aa04254f59b9 100644
--- a/docs/troubleshooting/faqs/General.mdx
+++ b/docs/troubleshooting/faqs/General.mdx
@@ -36,7 +36,7 @@ Some examples
```js title="eslint.config.mjs"
-export default tseslint.config(
+export default defineConfig(
// ... the rest of your config ...
{
rules: {
@@ -242,9 +242,10 @@ For example, the following config enables only the recommended config's type-che
{/* prettier-ignore */}
```js title="eslint.config.mjs"
import eslint from '@eslint/js';
+import { defineConfig } from 'eslint/config';
import tseslint from 'typescript-eslint';
-export default tseslint.config(
+export default defineConfig(
tseslint.configs.recommendedTypeCheckedOnly,
{
languageOptions: {
diff --git a/docs/troubleshooting/typed-linting/Monorepos.mdx b/docs/troubleshooting/typed-linting/Monorepos.mdx
index 85cc6ef264db..2364b9defe24 100644
--- a/docs/troubleshooting/typed-linting/Monorepos.mdx
+++ b/docs/troubleshooting/typed-linting/Monorepos.mdx
@@ -56,7 +56,7 @@ For each file being linted, the first matching project path will be used as its
```js title="eslint.config.mjs"
-export default tseslint.config(
+export default defineConfig(
eslint.configs.recommended,
tseslint.configs.recommendedTypeChecked,
{
@@ -108,7 +108,7 @@ Instead of globs that use `**` to recursively check all folders, prefer paths th
```js title="eslint.config.mjs"
-export default tseslint.config(
+export default defineConfig(
eslint.configs.recommended,
tseslint.configs.recommendedTypeChecked,
{
diff --git a/docs/troubleshooting/typed-linting/Performance.mdx b/docs/troubleshooting/typed-linting/Performance.mdx
index bc6ac0fa4769..66b9e2bfbe13 100644
--- a/docs/troubleshooting/typed-linting/Performance.mdx
+++ b/docs/troubleshooting/typed-linting/Performance.mdx
@@ -180,7 +180,7 @@ Instead of globs that use `**` to recursively check all folders, prefer paths th
import eslint from '@eslint/js';
import tseslint from 'typescript-eslint';
-export default tseslint.config(
+export default defineConfig(
eslint.configs.recommended,
tseslint.configs.recommendedRequiringTypeChecking,
{
diff --git a/docs/troubleshooting/typed-linting/index.mdx b/docs/troubleshooting/typed-linting/index.mdx
index 6681b1069b5d..5b76f5c53ad3 100644
--- a/docs/troubleshooting/typed-linting/index.mdx
+++ b/docs/troubleshooting/typed-linting/index.mdx
@@ -30,9 +30,10 @@ For example, to disable type-checked linting on all `.js` files:
```js title="eslint.config.mjs"
+import defineConfig from 'eslint/config';
import tseslint from 'typescript-eslint';
-export default tseslint.config(
+export default defineConfig(
// ... the rest of your config ...
{
files: ['**/*.js'],
@@ -69,7 +70,7 @@ You can combine ESLint's [overrides](https://eslint.org/docs/latest/use/configur
```js title="eslint.config.mjs"
-export default tseslint.config(
+export default defineConfig(
eslint.configs.recommended,
tseslint.configs.recommendedTypeChecked,
tseslint.configs.stylisticTypeChecked,
@@ -297,7 +298,7 @@ For example, if you use a specific `tsconfig.eslint.json` for linting, you'd spe
```js title="eslint.config.mjs"
-export default tseslint.config({
+export default defineConfig({
// ...
languageOptions: {
parserOptions: {
diff --git a/docs/users/Shared_Configurations.mdx b/docs/users/Shared_Configurations.mdx
index e77d68bcf6a2..ea4c554e37af 100644
--- a/docs/users/Shared_Configurations.mdx
+++ b/docs/users/Shared_Configurations.mdx
@@ -21,9 +21,10 @@ See [Getting Started > Quickstart](../getting-started/Quickstart.mdx) first to s
// @ts-check
import eslint from '@eslint/js';
+import { defineConfig } from 'eslint/config';
import tseslint from 'typescript-eslint';
-export default tseslint.config(
+export default defineConfig(
eslint.configs.recommended,
tseslint.configs.recommended,
);
@@ -37,7 +38,7 @@ If your project does not enable [typed linting](../getting-started/Typed_Linting
```js title="eslint.config.mjs"
-export default tseslint.config(
+export default defineConfig(
eslint.configs.recommended,
tseslint.configs.recommended,
tseslint.configs.stylistic,
@@ -70,7 +71,7 @@ If your project enables [typed linting](../getting-started/Typed_Linting.mdx), w
```js title="eslint.config.mjs"
-export default tseslint.config(
+export default defineConfig(
eslint.configs.recommended,
tseslint.configs.recommendedTypeChecked,
tseslint.configs.stylisticTypeChecked,
@@ -127,7 +128,7 @@ These rules are those whose reports are almost always for a bad practice and/or
{/* prettier-ignore */}
```js title="eslint.config.mjs"
-export default tseslint.config(
+export default defineConfig(
tseslint.configs.recommended,
);
```
@@ -156,7 +157,7 @@ Rules newly added in this configuration are similarly useful to those in `recomm
{/* prettier-ignore */}
```js title="eslint.config.mjs"
-export default tseslint.config(
+export default defineConfig(
tseslint.configs.recommendedTypeChecked,
);
```
@@ -185,7 +186,7 @@ Rules added in `strict` are more opinionated than recommended rules and might no
{/* prettier-ignore */}
```js title="eslint.config.mjs"
-export default tseslint.config(
+export default defineConfig(
tseslint.configs.strict,
);
```
@@ -224,7 +225,7 @@ Rules newly added in this configuration are similarly useful (and opinionated) t
{/* prettier-ignore */}
```js title="eslint.config.mjs"
-export default tseslint.config(
+export default defineConfig(
tseslint.configs.strictTypeChecked,
);
```
@@ -263,7 +264,7 @@ These rules are generally opinionated about enforcing simpler code patterns.
{/* prettier-ignore */}
```js title="eslint.config.mjs"
-export default tseslint.config(
+export default defineConfig(
tseslint.configs.stylistic,
);
```
@@ -295,7 +296,7 @@ Rules newly added in this configuration are similarly opinionated to those in `s
{/* prettier-ignore */}
```js title="eslint.config.mjs"
-export default tseslint.config(
+export default defineConfig(
tseslint.configs.stylisticTypeChecked,
);
```
@@ -362,7 +363,7 @@ If you use type-aware rules from other plugins, you will need to manually disabl
```js title="eslint.config.mjs"
-export default tseslint.config(
+export default defineConfig(
eslint.configs.recommended,
tseslint.configs.recommendedTypeChecked,
{
@@ -426,7 +427,7 @@ Additionally, it enables rules that promote using the more modern constructs Typ
```js title="eslint.config.mjs"
-export default tseslint.config(
+export default defineConfig(
eslint.configs.recommended,
tseslint.configs.eslintRecommended,
);
diff --git a/docs/users/What_About_Formatting.mdx b/docs/users/What_About_Formatting.mdx
index a070fdfccfb2..ace2aa4ebd97 100644
--- a/docs/users/What_About_Formatting.mdx
+++ b/docs/users/What_About_Formatting.mdx
@@ -50,11 +50,12 @@ Using this config by adding it to the end of your `extends`:
// @ts-check
import eslint from '@eslint/js';
+import { defineConfig } from 'eslint/config';
import someOtherConfig from 'eslint-config-other-configuration-that-enables-formatting-rules';
import prettierConfig from 'eslint-config-prettier';
import tseslint from 'typescript-eslint';
-export default tseslint.config(
+export default defineConfig(
eslint.configs.recommended,
tseslint.configs.recommended,
someOtherConfig,
diff --git a/eslint.config.mjs b/eslint.config.mjs
index b7b469b0dd63..9241cbee26a5 100644
--- a/eslint.config.mjs
+++ b/eslint.config.mjs
@@ -15,6 +15,7 @@ import reactPlugin from 'eslint-plugin-react';
import reactHooksPlugin from 'eslint-plugin-react-hooks';
import regexpPlugin from 'eslint-plugin-regexp';
import unicornPlugin from 'eslint-plugin-unicorn';
+import { defineConfig } from 'eslint/config';
import globals from 'globals';
import url from 'node:url';
import tseslint from 'typescript-eslint';
@@ -28,7 +29,7 @@ const restrictNamedDeclarations = {
selector: 'ExportNamedDeclaration[declaration=null][source=null]',
};
-export default tseslint.config(
+export default defineConfig(
// register all of the plugins up-front
{
name: 'register-all-plugins',
@@ -43,6 +44,7 @@ export default tseslint.config(
// @ts-expect-error -- https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/pull/1038
['jsx-a11y']: jsxA11yPlugin.flatConfigs.recommended.plugins['jsx-a11y'],
['perfectionist']: perfectionistPlugin,
+ // @ts-expect-error -- https://github.com/vitest-dev/eslint-plugin-vitest/issues/737
['vitest']: vitestPlugin,
// https://github.com/facebook/react/issues/28313
['react']: reactPlugin,
@@ -363,7 +365,6 @@ export default tseslint.config(
// test file specific configuration
{
extends: [
- // @ts-expect-error -- uses `string` instead of `off` | `readonly` | `writable` for the globals setting.
vitestPlugin.configs.env,
{
rules: {
diff --git a/packages/typescript-eslint/src/config-helper.ts b/packages/typescript-eslint/src/config-helper.ts
index 51456475734f..758052c62f56 100644
--- a/packages/typescript-eslint/src/config-helper.ts
+++ b/packages/typescript-eslint/src/config-helper.ts
@@ -88,6 +88,9 @@ export type ConfigArray = TSESLint.FlatConfig.ConfigArray;
* },
* );
* ```
+ *
+ * @deprecated ESLint core now provides this functionality via `defineConfig()`,
+ * which we now recommend instead. See {@link https://typescript-eslint.io/packages/typescript-eslint/#config-deprecated}.
*/
export function config(
...configs: InfiniteDepthConfigWithExtends[]
diff --git a/packages/typescript-eslint/tests/config-helper.test.ts b/packages/typescript-eslint/tests/config-helper.test.ts
index 8b4a151a32cf..7b3288df295f 100644
--- a/packages/typescript-eslint/tests/config-helper.test.ts
+++ b/packages/typescript-eslint/tests/config-helper.test.ts
@@ -2,6 +2,8 @@ import type { TSESLint } from '@typescript-eslint/utils';
import tseslint from '../src/index.js';
+/* eslint @typescript-eslint/no-deprecated: ["error", { "allow": [{ "from": "file", "name": "config", "path": "packages/typescript-eslint/src/config-helper.ts" }] }] */
+
describe('config helper', () => {
it('works without extends', () => {
expect(
diff --git a/packages/typescript-eslint/tests/type-compatibility.test-d.ts b/packages/typescript-eslint/tests/type-compatibility.test-d.ts
index b0e2f71b81d2..dfcf11cbd2f3 100644
--- a/packages/typescript-eslint/tests/type-compatibility.test-d.ts
+++ b/packages/typescript-eslint/tests/type-compatibility.test-d.ts
@@ -2,6 +2,8 @@ import { defineConfig } from 'eslint/config';
import tseslint from '../src/index';
+/* eslint @typescript-eslint/no-deprecated: ["error", { "allow": [{ "from": "file", "name": "config", "path": "packages/typescript-eslint/src/config-helper.ts" }] }] */
+
describe('test for compatibility with config helpers', () => {
test('exported plugin is compatible with tseslint.config()', () => {
tseslint.config({