eslint-config-typed 2.3.2 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (152) hide show
  1. package/README.md +319 -156
  2. package/dist/configs/plugins.d.mts +1 -1
  3. package/dist/configs/plugins.d.mts.map +1 -1
  4. package/dist/configs/plugins.mjs +5 -2
  5. package/dist/configs/plugins.mjs.map +1 -1
  6. package/dist/configs/react-base.d.mts.map +1 -1
  7. package/dist/configs/react-base.mjs +2 -0
  8. package/dist/configs/react-base.mjs.map +1 -1
  9. package/dist/configs/typescript-without-rules.mjs +4 -4
  10. package/dist/configs/typescript-without-rules.mjs.map +1 -1
  11. package/dist/configs/typescript.mjs +8 -8
  12. package/dist/configs/typescript.mjs.map +1 -1
  13. package/dist/entry-point.d.mts +1 -1
  14. package/dist/entry-point.d.mts.map +1 -1
  15. package/dist/entry-point.mjs +2 -1
  16. package/dist/entry-point.mjs.map +1 -1
  17. package/dist/index.mjs +3 -1
  18. package/dist/index.mjs.map +1 -1
  19. package/dist/plugins/index.d.mts +1 -0
  20. package/dist/plugins/index.d.mts.map +1 -1
  21. package/dist/plugins/index.mjs +1 -0
  22. package/dist/plugins/index.mjs.map +1 -1
  23. package/dist/plugins/react-coding-style/index.d.mts +2 -0
  24. package/dist/plugins/react-coding-style/index.d.mts.map +1 -0
  25. package/dist/plugins/react-coding-style/index.mjs +2 -0
  26. package/dist/plugins/react-coding-style/index.mjs.map +1 -0
  27. package/dist/plugins/react-coding-style/plugin.d.mts +3 -0
  28. package/dist/plugins/react-coding-style/plugin.d.mts.map +1 -0
  29. package/dist/plugins/react-coding-style/plugin.mjs +8 -0
  30. package/dist/plugins/react-coding-style/plugin.mjs.map +1 -0
  31. package/dist/plugins/react-coding-style/rules/ban-use-imperative-handle-hook.d.mts +5 -0
  32. package/dist/plugins/react-coding-style/rules/ban-use-imperative-handle-hook.d.mts.map +1 -0
  33. package/dist/plugins/react-coding-style/rules/ban-use-imperative-handle-hook.mjs +29 -0
  34. package/dist/plugins/react-coding-style/rules/ban-use-imperative-handle-hook.mjs.map +1 -0
  35. package/dist/plugins/react-coding-style/rules/component-name.d.mts +10 -0
  36. package/dist/plugins/react-coding-style/rules/component-name.d.mts.map +1 -0
  37. package/dist/plugins/react-coding-style/rules/component-name.mjs +78 -0
  38. package/dist/plugins/react-coding-style/rules/component-name.mjs.map +1 -0
  39. package/dist/plugins/react-coding-style/rules/component-var-type-annotation.d.mts +5 -0
  40. package/dist/plugins/react-coding-style/rules/component-var-type-annotation.d.mts.map +1 -0
  41. package/dist/plugins/react-coding-style/rules/component-var-type-annotation.mjs +41 -0
  42. package/dist/plugins/react-coding-style/rules/component-var-type-annotation.mjs.map +1 -0
  43. package/dist/plugins/react-coding-style/rules/import-style.d.mts +5 -0
  44. package/dist/plugins/react-coding-style/rules/import-style.d.mts.map +1 -0
  45. package/dist/plugins/react-coding-style/rules/import-style.mjs +45 -0
  46. package/dist/plugins/react-coding-style/rules/import-style.mjs.map +1 -0
  47. package/dist/plugins/react-coding-style/rules/index.d.mts +2 -0
  48. package/dist/plugins/react-coding-style/rules/index.d.mts.map +1 -0
  49. package/dist/plugins/react-coding-style/rules/index.mjs +2 -0
  50. package/dist/plugins/react-coding-style/rules/index.mjs.map +1 -0
  51. package/dist/plugins/react-coding-style/rules/props-type-annotation-style.d.mts +5 -0
  52. package/dist/plugins/react-coding-style/rules/props-type-annotation-style.d.mts.map +1 -0
  53. package/dist/plugins/react-coding-style/rules/props-type-annotation-style.mjs +44 -0
  54. package/dist/plugins/react-coding-style/rules/props-type-annotation-style.mjs.map +1 -0
  55. package/dist/plugins/react-coding-style/rules/react-memo-props-argument-name.d.mts +5 -0
  56. package/dist/plugins/react-coding-style/rules/react-memo-props-argument-name.d.mts.map +1 -0
  57. package/dist/plugins/react-coding-style/rules/react-memo-props-argument-name.mjs +55 -0
  58. package/dist/plugins/react-coding-style/rules/react-memo-props-argument-name.mjs.map +1 -0
  59. package/dist/plugins/react-coding-style/rules/react-memo-type-parameter.d.mts +5 -0
  60. package/dist/plugins/react-coding-style/rules/react-memo-type-parameter.d.mts.map +1 -0
  61. package/dist/plugins/react-coding-style/rules/react-memo-type-parameter.mjs +78 -0
  62. package/dist/plugins/react-coding-style/rules/react-memo-type-parameter.mjs.map +1 -0
  63. package/dist/plugins/react-coding-style/rules/rules.d.mts +14 -0
  64. package/dist/plugins/react-coding-style/rules/rules.d.mts.map +1 -0
  65. package/dist/plugins/react-coding-style/rules/rules.mjs +22 -0
  66. package/dist/plugins/react-coding-style/rules/rules.mjs.map +1 -0
  67. package/dist/plugins/react-coding-style/rules/shared.d.mts +5 -0
  68. package/dist/plugins/react-coding-style/rules/shared.d.mts.map +1 -0
  69. package/dist/plugins/react-coding-style/rules/shared.mjs +22 -0
  70. package/dist/plugins/react-coding-style/rules/shared.mjs.map +1 -0
  71. package/dist/plugins/react-coding-style/rules/use-memo-hooks-style.d.mts +5 -0
  72. package/dist/plugins/react-coding-style/rules/use-memo-hooks-style.d.mts.map +1 -0
  73. package/dist/plugins/react-coding-style/rules/use-memo-hooks-style.mjs +42 -0
  74. package/dist/plugins/react-coding-style/rules/use-memo-hooks-style.mjs.map +1 -0
  75. package/dist/plugins/total-functions/rules/common.d.mts +2 -1
  76. package/dist/plugins/total-functions/rules/common.d.mts.map +1 -1
  77. package/dist/plugins/total-functions/rules/fp-ts.d.mts +2 -1
  78. package/dist/plugins/total-functions/rules/fp-ts.d.mts.map +1 -1
  79. package/dist/plugins/total-functions/rules/unsafe-assignment-rule.d.mts +2 -1
  80. package/dist/plugins/total-functions/rules/unsafe-assignment-rule.d.mts.map +1 -1
  81. package/dist/rules/eslint-import-rules.d.mts +50 -47
  82. package/dist/rules/eslint-import-rules.d.mts.map +1 -1
  83. package/dist/rules/eslint-import-rules.mjs +55 -54
  84. package/dist/rules/eslint-import-rules.mjs.map +1 -1
  85. package/dist/rules/eslint-react-coding-style-rules.d.mts +13 -0
  86. package/dist/rules/eslint-react-coding-style-rules.d.mts.map +1 -0
  87. package/dist/rules/eslint-react-coding-style-rules.mjs +14 -0
  88. package/dist/rules/eslint-react-coding-style-rules.mjs.map +1 -0
  89. package/dist/rules/eslint-rules.d.mts +0 -57
  90. package/dist/rules/eslint-rules.d.mts.map +1 -1
  91. package/dist/rules/eslint-rules.mjs +1 -151
  92. package/dist/rules/eslint-rules.mjs.map +1 -1
  93. package/dist/rules/index.d.mts +1 -0
  94. package/dist/rules/index.d.mts.map +1 -1
  95. package/dist/rules/index.mjs +2 -1
  96. package/dist/rules/index.mjs.map +1 -1
  97. package/dist/rules/typescript-eslint-rules.mjs +1 -1
  98. package/dist/types/define-known-rules.d.mts +2 -2
  99. package/dist/types/define-known-rules.d.mts.map +1 -1
  100. package/dist/types/define-known-rules.mjs.map +1 -1
  101. package/dist/types/flat-config.d.mts.map +1 -1
  102. package/dist/types/rules/eslint-import-rules.d.mts +295 -336
  103. package/dist/types/rules/eslint-import-rules.d.mts.map +1 -1
  104. package/dist/types/rules/eslint-react-coding-style-rules.d.mts +148 -0
  105. package/dist/types/rules/eslint-react-coding-style-rules.d.mts.map +1 -0
  106. package/dist/types/rules/eslint-react-coding-style-rules.mjs +2 -0
  107. package/dist/types/rules/eslint-react-coding-style-rules.mjs.map +1 -0
  108. package/dist/types/rules/index.d.mts +1 -0
  109. package/dist/types/rules/index.d.mts.map +1 -1
  110. package/package.json +2 -5
  111. package/src/configs/plugins.mts +8 -3
  112. package/src/configs/react-base.mts +2 -0
  113. package/src/configs/typescript-without-rules.mts +4 -4
  114. package/src/configs/typescript.mts +8 -8
  115. package/src/entry-point.mts +2 -1
  116. package/src/plugins/index.mts +1 -0
  117. package/src/plugins/react-coding-style/README.md +36 -0
  118. package/src/plugins/react-coding-style/index.mts +1 -0
  119. package/src/plugins/react-coding-style/plugin.mts +6 -0
  120. package/src/plugins/react-coding-style/rules/ban-use-imperative-handle-hook.mts +31 -0
  121. package/src/plugins/react-coding-style/rules/ban-use-imperative-handle-hook.test.mts +40 -0
  122. package/src/plugins/react-coding-style/rules/component-name.mts +93 -0
  123. package/src/plugins/react-coding-style/rules/component-name.test.mts +72 -0
  124. package/src/plugins/react-coding-style/rules/component-var-type-annotation.mts +54 -0
  125. package/src/plugins/react-coding-style/rules/component-var-type-annotation.test.mts +62 -0
  126. package/src/plugins/react-coding-style/rules/import-style.mts +53 -0
  127. package/src/plugins/react-coding-style/rules/import-style.test.mts +63 -0
  128. package/src/plugins/react-coding-style/rules/index.mts +1 -0
  129. package/src/plugins/react-coding-style/rules/props-type-annotation-style.mts +59 -0
  130. package/src/plugins/react-coding-style/rules/props-type-annotation-style.test.mts +71 -0
  131. package/src/plugins/react-coding-style/rules/react-memo-props-argument-name.mts +70 -0
  132. package/src/plugins/react-coding-style/rules/react-memo-props-argument-name.test.mts +56 -0
  133. package/src/plugins/react-coding-style/rules/react-memo-type-parameter.mts +102 -0
  134. package/src/plugins/react-coding-style/rules/react-memo-type-parameter.test.mts +98 -0
  135. package/src/plugins/react-coding-style/rules/rules.mts +20 -0
  136. package/src/plugins/react-coding-style/rules/shared.mts +33 -0
  137. package/src/plugins/react-coding-style/rules/use-memo-hooks-style.mts +52 -0
  138. package/src/plugins/react-coding-style/rules/use-memo-hooks-style.test.mts +72 -0
  139. package/src/plugins/total-functions/rules/common.mts +1 -1
  140. package/src/plugins/total-functions/rules/fp-ts.mts +1 -1
  141. package/src/plugins/total-functions/rules/no-enums.mts +1 -1
  142. package/src/plugins/total-functions/rules/unsafe-assignment-rule.mts +1 -1
  143. package/src/rules/eslint-import-rules.mts +58 -55
  144. package/src/rules/eslint-react-coding-style-rules.mts +14 -0
  145. package/src/rules/eslint-rules.mts +0 -181
  146. package/src/rules/index.mts +1 -0
  147. package/src/rules/typescript-eslint-rules.mts +1 -1
  148. package/src/types/define-known-rules.mts +2 -0
  149. package/src/types/flat-config.mts +0 -1
  150. package/src/types/rules/eslint-import-rules.mts +305 -362
  151. package/src/types/rules/eslint-react-coding-style-rules.mts +166 -0
  152. package/src/types/rules/index.mts +1 -0
package/README.md CHANGED
@@ -36,7 +36,7 @@ A comprehensive ESLint configuration package with strongly-typed rule definition
36
36
  - [Rule Types](#rule-types)
37
37
  - [Customization](#customization)
38
38
  - [Override Specific Rules](#override-specific-rules)
39
- - [Use Type-Safe Rule Options](#use-type-safe-rule-options)
39
+ - [Use RulesOptions Types](#use-rulesoptions-types)
40
40
  - [Target Specific Files](#target-specific-files)
41
41
  - [Troubleshooting](#troubleshooting)
42
42
  - [Common Issues](#common-issues)
@@ -49,7 +49,7 @@ A comprehensive ESLint configuration package with strongly-typed rule definition
49
49
 
50
50
  ## Features
51
51
 
52
- - 🎯 **Type-Safe Configuration**: Fully typed ESLint rules and configurations for better IDE support
52
+ - 🎯 **Type-Safe Configuration**: Fully typed ESLint rules **and options** and configurations for better IDE support
53
53
  - 📦 **Pre-configured Setups**: Ready-to-use configurations for TypeScript, React, Preact, and popular testing frameworks
54
54
  - 📝 **Comprehensive Type Definitions**: Complete TypeScript types for all ESLint rules and options
55
55
  - 🔄 **ESLint Flat Config Support**: Built for the modern ESLint flat configuration system
@@ -75,15 +75,17 @@ All required ESLint plugins and dependencies are automatically installed.
75
75
 
76
76
  ## Quick Start
77
77
 
78
- Create an `eslint.config.js` file in your project root:
78
+ Create an `eslint.config.js` or `eslint.config.ts` file in your project root:
79
79
 
80
- ```js
80
+ ```tsx
81
81
  import {
82
82
  defineConfig,
83
+ defineKnownRules,
83
84
  eslintConfigForTypeScript,
84
85
  eslintConfigForVitest,
85
- defineKnownRules,
86
+ withDefaultOption,
86
87
  } from 'eslint-config-typed';
88
+
87
89
  // import * as path from 'node:path';
88
90
  // import * as url from 'node:url';
89
91
 
@@ -110,17 +112,15 @@ export default defineConfig([
110
112
  // You can override per-rule settings if necessary.
111
113
  {
112
114
  rules: defineKnownRules({
113
- '@typescript-eslint/no-explicit-any': 'warn',
115
+ '@typescript-eslint/no-explicit-any': withDefaultOption('warn'),
114
116
  '@typescript-eslint/prefer-readonly-parameter-types': 'off',
115
- 'react-hooks/exhaustive-deps': 'warn',
117
+ 'react-hooks/exhaustive-deps': withDefaultOption('warn'),
116
118
  'functional/no-let': [
117
119
  'error',
118
120
  {
119
121
  allowInForLoopInit: true,
120
122
  allowInFunctions: false,
121
- ignoreIdentifierPattern: ignorePattern.filter(
122
- (p) => p !== '^draft',
123
- ),
123
+ ignoreIdentifierPattern: ['^mut_', '^_mut_', '^#mut_'],
124
124
  },
125
125
  ],
126
126
  }),
@@ -151,14 +151,20 @@ npm run lint:fix
151
151
 
152
152
  `defineConfig` wraps your flat configuration array so JavaScript config files get full IntelliSense without relying on JSDoc casts. It keeps literal types intact while returning the config unchanged at runtime.
153
153
 
154
- ```js
155
- import { defineConfig, eslintConfigForTypeScript } from 'eslint-config-typed';
154
+ ```tsx
155
+ import {
156
+ defineConfig,
157
+ defineKnownRules,
158
+ eslintConfigForTypeScript,
159
+ } from 'eslint-config-typed';
160
+
161
+ const thisDir = import.meta.dirname;
156
162
 
157
163
  export default defineConfig([
158
164
  ...eslintConfigForTypeScript({
159
- tsconfigRootDir: import.meta.dirname,
165
+ tsconfigRootDir: thisDir,
160
166
  tsconfigFileName: './tsconfig.json',
161
- packageDirs: [import.meta.dirname],
167
+ packageDirs: [thisDir],
162
168
  }),
163
169
  {
164
170
  rules: defineKnownRules({
@@ -170,93 +176,195 @@ export default defineConfig([
170
176
 
171
177
  This is equivalent to:
172
178
 
173
- ```js
174
- import { eslintConfigForTypeScript } from 'eslint-config-typed';
179
+ ```tsx
180
+ import {
181
+ defineKnownRules,
182
+ eslintConfigForTypeScript,
183
+ type FlatConfig,
184
+ } from 'eslint-config-typed';
185
+
186
+ const thisDir = import.meta.dirname;
175
187
 
176
- /** @type {import('@typescript-eslint/utils/ts-eslint').FlatConfig[]} */
177
188
  export default [
178
189
  ...eslintConfigForTypeScript({
179
- tsconfigRootDir: import.meta.dirname,
190
+ tsconfigRootDir: thisDir,
180
191
  tsconfigFileName: './tsconfig.json',
181
- packageDirs: [import.meta.dirname],
192
+ packageDirs: [thisDir],
182
193
  }),
183
194
  {
184
195
  rules: defineKnownRules({
185
196
  // ...
186
197
  }),
187
198
  },
188
- ];
199
+ ] satisfies readonly FlatConfig[];
189
200
  ```
190
201
 
191
202
  ### defineKnownRules utility
192
203
 
193
- `defineKnownRules` is a helper designed for the `rules` field in ESLint flat configs. It keeps the returned object untouched while giving you type-safe rule names and option inference in editors. When you wrap your overrides with this function you can rely on:
204
+ `defineKnownRules` is a helper designed for the `rules` field in ESLint flat configs. It keeps the returned object untouched while giving you **type-safe rule names and option inference** in editors (like biome.json). When you wrap your overrides with this function you can rely on:
194
205
 
195
206
  - autocomplete and early feedback for rule identifiers, eliminating typo-prone string literals;
196
207
  - strongly typed options for every plugin rule that ships with `eslint-config-typed`, so you can discover valid properties without leaving your editor;
197
208
  - a zero-cost runtime helper—because the object is returned as-is, it blends seamlessly into any flat config block.
198
209
 
210
+ ```tsx
211
+ import {
212
+ defineKnownRules,
213
+ eslintConfigForTypeScript,
214
+ type FlatConfig,
215
+ } from 'eslint-config-typed';
216
+
217
+ const thisDir = import.meta.dirname;
218
+
219
+ export default [
220
+ ...eslintConfigForTypeScript({
221
+ tsconfigRootDir: thisDir,
222
+ tsconfigFileName: './tsconfig.json',
223
+ packageDirs: [thisDir],
224
+ }),
225
+ {
226
+ rules: defineKnownRules({
227
+ // @ts-expect-error typo of rule name
228
+ 'no-restricted-globalsSSSS': 'error',
229
+ // ~~~~~~~~~~~~~~~~~~~~~~~
230
+ }),
231
+ },
232
+ {
233
+ rules: defineKnownRules({
234
+ 'no-unsafe-optional-chaining': [
235
+ 'error',
236
+ // @ts-expect-error typo of an option key
237
+ { disallowArithmeticOperatorsSSSSS: true },
238
+ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
239
+ ],
240
+ }),
241
+ },
242
+ ] satisfies FlatConfig[];
243
+ ```
244
+
199
245
  ### withDefaultOption utility
200
246
 
201
247
  `withDefaultOption` is a companion helper that highlights rules which ship with option objects. It maps the familiar severity strings to the numeric values ESLint expects: `withDefaultOption('error')` returns `2`, and `withDefaultOption('warn')` returns `1`. Within `defineKnownRules`, rules that provide options require one of these helpers when you want to keep the defaults and only adjust severity. This convention visually distinguishes rules that contain options, reminding users that a rule has configurable options.
202
248
 
203
249
  `defineKnownRules` also reserves `0` for deprecated rules. The resulting severity matrix looks like this:
204
250
 
205
- | Rule type | Allowed severity values in `defineKnownRules` |
206
- | :------------------- | :------------------------------------------------------------- |
207
- | Deprecated rule | `0` |
208
- | Rule without options | `"off"`, `"warn"`, `"error"` |
209
- | Rule with options | `"off"`, `1`, `2`, `["warn", <option>]`, `["error", <option>]` |
251
+ | Rule type | Allowed severity values in `defineKnownRules` |
252
+ | :------------------- | :-------------------------------------------- | ------ | -------- | ------- | ------------------- |
253
+ | Deprecated rule | `0` |
254
+ | Rule without options | `"off" | "warn" | "error"` |
255
+ | Rule with options | `"off" | 1 | 2 | ["warn" | "error", <option>]` |
256
+
257
+ ```tsx
258
+ import {
259
+ defineKnownRules,
260
+ eslintConfigForTypeScript,
261
+ withDefaultOption,
262
+ type FlatConfig,
263
+ } from 'eslint-config-typed';
264
+
265
+ const thisDir = import.meta.dirname;
266
+
267
+ export default [
268
+ ...eslintConfigForTypeScript({
269
+ tsconfigRootDir: thisDir,
270
+ tsconfigFileName: './tsconfig.json',
271
+ packageDirs: [thisDir],
272
+ }),
273
+ {
274
+ rules: defineKnownRules({
275
+ // @ts-expect-error Simply passing the string "error" to a rule with options is not allowed
276
+ 'no-restricted-globals': 'error',
277
+ // ~~~~~~~~~~~~~~~~~~~~
278
+ // ^ Type Error! (Because "no-restricted-globals" has options)
279
+ // NOTE: In addition, some rules, such as "no-restricted-syntax" "and no-restricted-globals", have no effect unless you set the option.
280
+
281
+ // OK
282
+ 'object-shorthand': withDefaultOption('error'),
283
+
284
+ // OK (options are set explicitly)
285
+ 'no-unsafe-optional-chaining': [
286
+ 'error',
287
+ { disallowArithmeticOperators: true },
288
+ ],
289
+ }),
290
+ },
291
+ ] satisfies FlatConfig[];
292
+ ```
293
+
294
+ ### TypeScript Configuration Files
295
+
296
+ You can also write your eslint config in `.ts` or `.mts` format, all you need to do is run `npm add -D jiti`.
297
+
298
+ ```tsx
299
+ import {
300
+ eslintConfigForTypeScript,
301
+ eslintConfigForVitest,
302
+ type FlatConfig,
303
+ } from 'eslint-config-typed';
304
+
305
+ const thisDir = import.meta.dirname;
306
+
307
+ export default [
308
+ ...eslintConfigForTypeScript({
309
+ tsconfigRootDir: thisDir,
310
+ tsconfigFileName: './tsconfig.json',
311
+ packageDirs: [thisDir],
312
+ }),
313
+ eslintConfigForVitest(),
314
+ ] satisfies FlatConfig[];
315
+ ```
316
+
317
+ For details, see <https://eslint.org/docs/latest/use/configure/configuration-files#typescript-configuration-files>.
210
318
 
211
319
  ## Configuration Examples
212
320
 
213
321
  ### TypeScript + React Project
214
322
 
215
- ```js
323
+ ```tsx
216
324
  import {
217
- defineConfig,
218
- eslintConfigForTypeScript,
219
- eslintConfigForReact,
220
- eslintConfigForNodeJs,
221
325
  defineKnownRules,
326
+ eslintConfigForNodeJs,
327
+ eslintConfigForReact,
328
+ eslintConfigForTypeScript,
329
+ type FlatConfig,
222
330
  } from 'eslint-config-typed';
223
331
 
224
332
  const thisDir = import.meta.dirname;
225
333
 
226
- export default defineConfig([
227
- { ignores: ['**/dist/**', '**/build/**', '**/.next/**'] },
334
+ export default [
335
+ { ignores: ['**/dist/**', '**/build/**', '**/.next/**', 'public/**'] },
228
336
  ...eslintConfigForTypeScript({
229
337
  tsconfigRootDir: thisDir,
230
338
  tsconfigFileName: './tsconfig.json',
231
339
  packageDirs: [thisDir],
232
340
  }),
233
- eslintConfigForReact(['src/**']),
341
+ ...eslintConfigForReact(['src/**']),
234
342
  eslintConfigForNodeJs(['scripts/**', 'configs/**']),
235
343
  {
236
344
  files: ['scripts/**', 'configs/**'],
237
345
  rules: defineKnownRules({
238
346
  '@typescript-eslint/explicit-function-return-type': 'off',
239
347
  'no-await-in-loop': 'off',
240
- 'import/no-unassigned-import': 'off',
241
- 'import/no-internal-modules': 'off',
242
- 'import/no-default-export': 'off',
243
- 'import/no-extraneous-dependencies': 'off',
348
+ 'import-x/no-unassigned-import': 'off',
349
+ 'import-x/no-internal-modules': 'off',
350
+ 'import-x/no-default-export': 'off',
351
+ 'import-x/no-extraneous-dependencies': 'off',
244
352
  }),
245
353
  },
246
- ]);
354
+ ] satisfies FlatConfig[];
247
355
  ```
248
356
 
249
357
  ### Node.js TypeScript Project
250
358
 
251
- ```js
359
+ ```tsx
252
360
  import {
253
- defineConfig,
254
- eslintConfigForTypeScript,
255
- eslintConfigForNodeJs,
256
361
  defineKnownRules,
362
+ eslintConfigForNodeJs,
363
+ eslintConfigForTypeScript,
364
+ type FlatConfig,
257
365
  } from 'eslint-config-typed';
258
366
 
259
- export default defineConfig([
367
+ export default [
260
368
  { ignores: ['**/dist/**', '**/node_modules/**'] },
261
369
  ...eslintConfigForTypeScript({
262
370
  tsconfigRootDir: import.meta.dirname,
@@ -268,25 +376,23 @@ export default defineConfig([
268
376
  rules: defineKnownRules({
269
377
  // Allow console in Node.js
270
378
  'no-console': 'off',
271
- // Allow process.env access
272
- 'no-process-env': 'off',
273
379
  }),
274
380
  },
275
- ]);
381
+ ] satisfies FlatConfig[];
276
382
  ```
277
383
 
278
384
  ### React + Testing Libraries
279
385
 
280
- ```js
386
+ ```tsx
281
387
  import {
282
- defineConfig,
283
- eslintConfigForTypeScript,
284
388
  eslintConfigForReact,
285
- eslintConfigForVitest,
286
389
  eslintConfigForTestingLibrary,
390
+ eslintConfigForTypeScript,
391
+ eslintConfigForVitest,
392
+ type FlatConfig,
287
393
  } from 'eslint-config-typed';
288
394
 
289
- export default defineConfig([
395
+ export default [
290
396
  { ignores: ['**/dist/**', '**/coverage/**'] },
291
397
  ...eslintConfigForTypeScript({
292
398
  tsconfigRootDir: import.meta.dirname,
@@ -296,7 +402,7 @@ export default defineConfig([
296
402
  ...eslintConfigForReact(),
297
403
  eslintConfigForVitest(),
298
404
  eslintConfigForTestingLibrary(),
299
- ]);
405
+ ] satisfies FlatConfig[];
300
406
  ```
301
407
 
302
408
  ## VS Code Integration
@@ -310,36 +416,13 @@ Add the following to `.vscode/settings.json` for proper ESLint integration:
310
416
  "mode": "auto"
311
417
  }
312
418
  ],
313
- "eslint.experimental.useFlatConfig": true,
314
- "editor.codeActionsOnSave": {
315
- "source.fixAll.eslint": "explicit"
316
- }
419
+ "eslint.experimental.useFlatConfig": true
420
+ // "editor.codeActionsOnSave": {
421
+ // "source.fixAll.eslint": "explicit"
422
+ // }
317
423
  }
318
424
  ```
319
425
 
320
- ## TypeScript Configuration Files
321
-
322
- You can also write your eslint config in `.ts` or `.mts` format, all you need to do is run `npm add -D jiti`.
323
-
324
- ```ts
325
- import {
326
- eslintConfigForTypeScript,
327
- eslintConfigForVitest,
328
- type FlatConfig,
329
- } from 'eslint-config-typed';
330
-
331
- export default [
332
- ...eslintConfigForTypeScript({
333
- tsconfigRootDir: thisDir,
334
- tsconfigFileName: './tsconfig.json',
335
- packageDirs: [thisDir],
336
- }),
337
- eslintConfigForVitest(),
338
- ] satisfies FlatConfig[];
339
- ```
340
-
341
- For details, see <https://eslint.org/docs/latest/use/configure/configuration-files#typescript-configuration-files>.
342
-
343
426
  ## Included plugins
344
427
 
345
428
  - @typescript-eslint/eslint-plugin
@@ -351,7 +434,7 @@ For details, see <https://eslint.org/docs/latest/use/configure/configuration-fil
351
434
  - eslint-plugin-sort-destructure-keys
352
435
  - eslint-plugin-security
353
436
  - eslint-plugin-promise
354
- - eslint-plugin-import
437
+ - eslint-plugin-import-x
355
438
  - eslint-plugin-strict-dependencies
356
439
  - eslint-plugin-tree-shakable (Reimplemented in this repository to support flat config)
357
440
  - eslint-plugin-react
@@ -370,7 +453,7 @@ For details, see <https://eslint.org/docs/latest/use/configure/configuration-fil
370
453
 
371
454
  ### Configuration Functions
372
455
 
373
- These functions return arrays of ESLint flat configurations:
456
+ These functions return (arrays of) ESLint flat configuration(s):
374
457
 
375
458
  #### Base Configurations
376
459
 
@@ -385,7 +468,7 @@ These functions return arrays of ESLint flat configurations:
385
468
 
386
469
  - **`eslintConfigForReact(options?)`** - React configuration with hooks and JSX rules
387
470
  - `eslintConfigForBrowser` is included in this configuration
388
- - **`eslintConfigForPreact(options?)`** - Preact configuration (lighter React alternative)
471
+ - **`eslintConfigForPreact(options?)`** - Preact (lighter React alternative) configuration
389
472
  - `eslintConfigForBrowser` is included in this configuration
390
473
  - **`eslintConfigForVitest(options?)`** - Vitest testing framework configuration
391
474
  - **`eslintConfigForJest(options?)`** - Jest testing framework configuration
@@ -401,31 +484,32 @@ These functions return arrays of ESLint flat configurations:
401
484
 
402
485
  Pre-configured rule sets that can be imported and customized:
403
486
 
404
- | Rule set | Plugin name | Description |
405
- | :----------------------------------------- | :------------------------------------- | :----------------------------------- |
406
- | **`eslintRules`** | (eslint) | Core ESLint rules |
407
- | **`typescriptEslintRules`** | `@typescript-eslint/eslint-plugin` | TypeScript-specific ESLint rules |
408
- | **`eslintFunctionalRules`** | `eslint-plugin-functional` | Functional programming style rules |
409
- | **`eslintTotalFunctionsRules`** | `eslint-plugin-total-functions` | Functional programming style rules |
410
- | **`eslintUnicornRules`** | `eslint-plugin-unicorn` | Unicorn plugin rules for better code |
411
- | **`eslintArrayFuncRules`** | `eslint-plugin-array-func` | Array function preference rules |
412
- | **`eslintPreferArrowFunctionRules`** | `eslint-plugin-prefer-arrow-functions` | Arrow function preference rules |
413
- | **`eslintPluginSortDestructureKeysRules`** | `eslint-plugin-sort-destructure-keys` | Object destructuring rules |
414
- | **`eslintPromiseRules`** | `eslint-plugin-promise` | Promise handling rules |
415
- | **`eslintImportsRules`** | `eslint-plugin-import` | Import/export rules |
416
- | **`eslintSecurityRules`** | `eslint-plugin-security` | Security best practices |
417
- | **`eslintTreeShakableRules`** | `eslint-plugin-tree-shakable` | Tree-shaking optimization rules |
418
- | **`eslintReactRules`** | `eslint-plugin-react` | React-specific rules |
419
- | **`eslintReactHooksRules`** | `eslint-plugin-react-hooks` | React Hooks rules |
420
- | **`eslintReactPerfRules`** | `eslint-plugin-react-perf` | React performance optimization rules |
421
- | **`eslintReactRefreshRules`** | `eslint-plugin-react-refresh` | React Refresh (HMR) rules |
422
- | **`eslintJsxA11yRules`** | `eslint-plugin-jsx-a11y` | Accessibility rules for JSX |
423
- | **`eslintVitestRules`** | `eslint-plugin-vitest` | Vitest-specific rules |
424
- | **`eslintJestRules`** | `eslint-plugin-jest` | Jest-specific rules |
425
- | **`eslintTestingLibraryRules`** | `eslint-plugin-testing-library` | Testing Library rules |
426
- | **`eslintPlaywrightRules`** | `eslint-plugin-playwright` | Playwright-specific rules |
427
- | **`eslintCypressRules`** | `eslint-plugin-cypress` | Cypress-specific rules |
428
- | **`eslintPluginRules`** | `eslint-plugin-eslint-plugin` | eslint-plugin development rules |
487
+ | Rule set | Plugin name | Description |
488
+ | :----------------------------------------- | :------------------------------------- | :-------------------------------------- |
489
+ | **`eslintRules`** | (eslint) | Core ESLint rules |
490
+ | **`typescriptEslintRules`** | `@typescript-eslint/eslint-plugin` | TypeScript-specific ESLint rules |
491
+ | **`eslintFunctionalRules`** | `eslint-plugin-functional` | Functional programming style rules |
492
+ | **`eslintTotalFunctionsRules`** | `eslint-plugin-total-functions` | Functional programming style rules |
493
+ | **`eslintUnicornRules`** | `eslint-plugin-unicorn` | Unicorn plugin rules for better code |
494
+ | **`eslintArrayFuncRules`** | `eslint-plugin-array-func` | Array function preference rules |
495
+ | **`eslintPreferArrowFunctionRules`** | `eslint-plugin-prefer-arrow-functions` | Arrow function preference rules |
496
+ | **`eslintPluginSortDestructureKeysRules`** | `eslint-plugin-sort-destructure-keys` | Object destructuring rules |
497
+ | **`eslintPromiseRules`** | `eslint-plugin-promise` | Promise handling rules |
498
+ | **`eslintImportsRules`** | `eslint-plugin-import-x` | Import/export rules |
499
+ | **`eslintSecurityRules`** | `eslint-plugin-security` | Security best practices |
500
+ | **`eslintTreeShakableRules`** | `eslint-plugin-tree-shakable` | Tree-shaking optimization rules |
501
+ | **`eslintReactRules`** | `eslint-plugin-react` | React-specific rules |
502
+ | **`eslintReactHooksRules`** | `eslint-plugin-react-hooks` | React Hooks rules |
503
+ | **`eslintReactPerfRules`** | `eslint-plugin-react-perf` | React performance optimization rules |
504
+ | **`eslintReactRefreshRules`** | `eslint-plugin-react-refresh` | React Refresh (HMR) rules |
505
+ | **`eslintReactCodingStyleRules`** | `eslint-plugin-react-coding-style` | Opinionated React component style rules |
506
+ | **`eslintJsxA11yRules`** | `eslint-plugin-jsx-a11y` | Accessibility rules for JSX |
507
+ | **`eslintVitestRules`** | `eslint-plugin-vitest` | Vitest-specific rules |
508
+ | **`eslintJestRules`** | `eslint-plugin-jest` | Jest-specific rules |
509
+ | **`eslintTestingLibraryRules`** | `eslint-plugin-testing-library` | Testing Library rules |
510
+ | **`eslintPlaywrightRules`** | `eslint-plugin-playwright` | Playwright-specific rules |
511
+ | **`eslintCypressRules`** | `eslint-plugin-cypress` | Cypress-specific rules |
512
+ | **`eslintPluginRules`** | `eslint-plugin-eslint-plugin` | eslint-plugin development rules |
429
513
 
430
514
  ### Exported Pre-configured Rule Options
431
515
 
@@ -434,7 +518,6 @@ Pre-configured rule sets that can be imported and customized:
434
518
  | **`restrictedGlobals`** | `no-restricted-globals` | Array of restricted global variables |
435
519
  | **`restrictedGlobalsForBrowser`** | `no-restricted-globals` | Browser-environment-specific restricted globals |
436
520
  | **`restrictedSyntax`** | `no-restricted-syntax` | Disallows the `in` operator, `Object.prototype.hasOwnProperty.call` (suggests using `Object.hasOwn`), and `new Array(*)` syntax (suggests using `Array.from`) |
437
- | **`restrictedSyntaxForReact`** | `no-restricted-syntax` | Rule set to restrict React component styling |
438
521
 
439
522
  You can find other pre-configured rule options by traversing the pre-defined rules object like this:
440
523
 
@@ -449,16 +532,23 @@ The shape of the rule option varies depending on the rule, so please check the c
449
532
  - `eslint-plugin-total-functions` with support for Flat Config
450
533
  - **`eslintPluginTreeShakable`**
451
534
  - `eslint-plugin-tree-shakable` with support for Flat Config
535
+ - **`eslintPluginReactCodingStyle`**
536
+ - Custom ESLint plugin that codifies this repository's React memo component conventions (namespace imports, `React.memo<Props>`, arrow props naming, etc.). See [`src/plugins/react-coding-style/README.md`](src/plugins/react-coding-style/README.md) for the rationale and examples.
537
+ - Provides rules such as `react-coding-style/import-style`, `react-coding-style/component-var-type-annotation`, `react-coding-style/react-memo-type-parameter`, `react-coding-style/react-memo-props-argument-name`, `react-coding-style/props-type-annotation-style`, and `react-coding-style/react-hooks-definition-style`.
452
538
  - **`eslintPluginCustom`** - Custom ESLint plugin with additional rules
453
539
  - Currently, this plugin only provides the `custom/no-restricted-syntax` rule (which duplicates ESLint's `no-restricted-syntax` rule).
454
540
  - Can be used to set the error level to `error` or `warn` as needed.
455
541
 
456
542
  Example:
457
543
 
458
- ```js
459
- import { eslintRules } from 'eslint-config-typed';
544
+ ```tsx
545
+ import {
546
+ defineKnownRules,
547
+ eslintRules,
548
+ type FlatConfig,
549
+ } from 'eslint-config-typed';
460
550
 
461
- export default defineConfig([
551
+ export default [
462
552
  // ...
463
553
  {
464
554
  rules: defineKnownRules({
@@ -478,7 +568,7 @@ export default defineConfig([
478
568
  ],
479
569
  }),
480
570
  },
481
- ]);
571
+ ] satisfies FlatConfig[];
482
572
  ```
483
573
 
484
574
  ### Type Definitions
@@ -488,9 +578,13 @@ All rules and configurations come with complete TypeScript type definitions:
488
578
  #### Core Types
489
579
 
490
580
  - **`FlatConfig`** - ESLint flat configuration type
581
+ - `= DeepReadonly<import('@typescript-eslint/utils/ts-eslint').FlatConfig>`
491
582
  - **`ESLintPlugin`** - ESLint plugin type
583
+ - `= DeepReadonly<import('@typescript-eslint/utils/ts-eslint').FlatConfig.Plugin>`
492
584
  - **`Rule`** - ESLint rule definition type
585
+ - `= DeepReadonly<import('@eslint/core').RuleDefinition>`
493
586
  - **`Rules`** - Collection of rules type
587
+ - `= Readonly<Record<string, Rule>>`
494
588
 
495
589
  #### Rule Types
496
590
 
@@ -533,15 +627,27 @@ The pre-configured rules of `eslint-config-typed` are opinionated settings that
533
627
 
534
628
  You can override any rule by adding a configuration object after the preset configurations:
535
629
 
536
- ```js
537
- import { typescriptEslintRules } from 'eslint-config-typed';
630
+ ```tsx
631
+ import {
632
+ defineKnownRules,
633
+ eslintConfigForTypeScript,
634
+ type FlatConfig,
635
+ typescriptEslintRules,
636
+ withDefaultOption,
637
+ } from 'eslint-config-typed';
538
638
 
539
- export default defineConfig([
540
- ...eslintConfigForTypeScript(options),
639
+ const thisDir = import.meta.dirname;
640
+
641
+ export default [
642
+ ...eslintConfigForTypeScript({
643
+ tsconfigRootDir: thisDir,
644
+ tsconfigFileName: './tsconfig.json',
645
+ packageDirs: [thisDir],
646
+ }),
541
647
  {
542
648
  rules: defineKnownRules({
543
649
  // Downgrade to warning (Option settings are inherited)
544
- '@typescript-eslint/no-explicit-any': 'warn',
650
+ '@typescript-eslint/no-explicit-any': withDefaultOption('warn'),
545
651
  // Disable a rule
546
652
  '@typescript-eslint/prefer-readonly-parameter-types': 'off',
547
653
  // Configure with options
@@ -567,19 +673,18 @@ export default defineConfig([
567
673
  ],
568
674
  }),
569
675
  },
570
- ]);
676
+ ] satisfies FlatConfig[];
571
677
  ```
572
678
 
573
- ### Use Type-Safe Rule Options
679
+ ### Use RulesOptions Types
574
680
 
575
681
  Leverage TypeScript for type-safe rule configuration:
576
682
 
577
- ```ts
683
+ ```tsx
578
684
  // configs/restricted-syntax-defs.mjs
579
685
 
580
- import { eslintRules } from 'eslint-config-typed';
686
+ import { eslintRules, type EslintRulesOption } from 'eslint-config-typed';
581
687
 
582
- /** @type {import("eslint-config-typed").EslintRulesOption["no-restricted-syntax"]} */
583
688
  export const restrictedSyntax = [
584
689
  ...eslintRules['no-restricted-syntax'].slice(1),
585
690
  {
@@ -589,31 +694,54 @@ export const restrictedSyntax = [
589
694
  message:
590
695
  'The variable type T should be annotated as `React.useMemo<T>` or `const v: T = React.useMemo(...)`.',
591
696
  },
592
- ];
697
+ ] satisfies EslintRulesOption['no-restricted-syntax'];
593
698
  ```
594
699
 
595
- ```ts
596
- // eslint.config.js
700
+ ```tsx
701
+ // eslint.config.mts
702
+
703
+ import {
704
+ defineKnownRules,
705
+ eslintConfigForTypeScript,
706
+ type FlatConfig,
707
+ } from 'eslint-config-typed';
708
+ import { restrictedSyntax } from './restricted-syntax-defs.mjs';
597
709
 
598
- import { restrictedSyntax } from './configs/restricted-syntax-defs.mjs';
710
+ const thisDir = import.meta.dirname;
599
711
 
600
- export default defineConfig([
601
- ...eslintConfigForTypeScript(options),
712
+ export default [
713
+ ...eslintConfigForTypeScript({
714
+ tsconfigRootDir: thisDir,
715
+ tsconfigFileName: './tsconfig.json',
716
+ packageDirs: [thisDir],
717
+ }),
602
718
  {
603
719
  rules: defineKnownRules({
604
- 'no-restricted-syntax': ['error', restrictedSyntax],
720
+ 'no-restricted-syntax': ['error', ...restrictedSyntax],
605
721
  }),
606
722
  },
607
- ]);
723
+ ] satisfies readonly FlatConfig[];
608
724
  ```
609
725
 
610
726
  ### Target Specific Files
611
727
 
612
728
  Apply different rules to different file patterns:
613
729
 
614
- ```js
615
- export default defineConfig([
616
- ...eslintConfigForTypeScript(options),
730
+ ```tsx
731
+ import {
732
+ defineKnownRules,
733
+ eslintConfigForTypeScript,
734
+ type FlatConfig,
735
+ } from 'eslint-config-typed';
736
+
737
+ const thisDir = import.meta.dirname;
738
+
739
+ export default [
740
+ ...eslintConfigForTypeScript({
741
+ tsconfigRootDir: thisDir,
742
+ tsconfigFileName: './tsconfig.json',
743
+ packageDirs: [thisDir],
744
+ }),
617
745
  {
618
746
  files: ['**/*.test.ts', '**/*.spec.ts'],
619
747
  rules: defineKnownRules({
@@ -628,10 +756,10 @@ export default defineConfig([
628
756
  rules: defineKnownRules({
629
757
  // Allow console in scripts
630
758
  'no-await-in-loop': 'off',
631
- 'import/no-unassigned-import': 'off',
759
+ 'import-x/no-unassigned-import': 'off',
632
760
  }),
633
761
  },
634
- ]);
762
+ ] satisfies FlatConfig[];
635
763
  ```
636
764
 
637
765
  ## Troubleshooting
@@ -642,33 +770,41 @@ export default defineConfig([
642
770
 
643
771
  Ensure the paths are correct:
644
772
 
645
- ```js
773
+ ```tsx
774
+ import {
775
+ eslintConfigForTypeScript,
776
+ type FlatConfig,
777
+ } from 'eslint-config-typed';
778
+
646
779
  const thisDir = import.meta.dirname;
647
780
 
648
- export default defineConfig([
649
- ...eslintConfigForTypeScript({
650
- tsconfigRootDir: thisDir, // Must be absolute path
651
- tsconfigFileName: './tsconfig.json', // Relative to tsconfigRootDir
652
- packageDirs: [thisDir],
653
- }),
654
- ]);
781
+ export default eslintConfigForTypeScript({
782
+ tsconfigRootDir: thisDir, // Must be absolute path
783
+ tsconfigFileName: './tsconfig.json', // Relative to tsconfigRootDir
784
+ packageDirs: [thisDir],
785
+ }) satisfies readonly FlatConfig[];
655
786
  ```
656
787
 
657
788
  #### 2. Import resolution errors
658
789
 
659
790
  The `packageDirs` option helps ESLint resolve imports correctly in monorepos:
660
791
 
661
- ```js
662
- export default defineConfig([
663
- ...eslintConfigForTypeScript({
664
- tsconfigRootDir: thisDir,
665
- tsconfigFileName: './tsconfig.json',
666
- packageDirs: [
667
- path.resolve(thisDir, '../../..'), // Monorepo root
668
- thisDir, // Current package
669
- ],
670
- }),
671
- ]);
792
+ ```tsx
793
+ import {
794
+ eslintConfigForTypeScript,
795
+ type FlatConfig,
796
+ } from 'eslint-config-typed';
797
+
798
+ const thisDir = import.meta.dirname;
799
+
800
+ export default eslintConfigForTypeScript({
801
+ tsconfigRootDir: thisDir,
802
+ tsconfigFileName: './tsconfig.json',
803
+ packageDirs: [
804
+ path.resolve(thisDir, '../../..'), // Monorepo root
805
+ thisDir, // Current package
806
+ ],
807
+ }) satisfies readonly FlatConfig[];
672
808
  ```
673
809
 
674
810
  #### 3. Performance issues
@@ -682,9 +818,36 @@ For large projects, consider:
682
818
  - Running ESLint with `--cache` flag
683
819
  - Limiting the scope of type-aware rules
684
820
 
821
+ #### 4. How to Use import-x/no-unused-modules
822
+
823
+ [`import-x/no-unused-modules`](https://github.com/un-ts/eslint-plugin-import-x/blob/v4.16.1/docs/rules/no-unused-modules.md) reports exported values that are never imported anywhere else. The rule still relies on ESLint’s classic configuration loader to discover ignore patterns, so a flat-config-only setup is not enough. For this to work, you need to place a `.eslintrc.cjs` file along with `eslint.config.mts`.
824
+
825
+ ```cjs
826
+ // .eslintrc.cjs
827
+ module.exports = {
828
+ ignorePatterns: ['**/node_modules/**', 'dist', '.eslintrc.cjs'],
829
+ };
830
+ ```
831
+
832
+ The flat config then enables the rule for our source tree and marks the public federation module as an allowed unused export:
833
+
834
+ ```ts
835
+ // eslint.config.mts (excerpt)
836
+ {
837
+ files: ['src/**'],
838
+ rules: defineKnownRules({
839
+ 'import-x/no-unused-modules': [
840
+ 'error',
841
+ { unusedExports: true, ignoreExports: ['src/entry-point.mts'] },
842
+ ],
843
+ }),
844
+ },
845
+ ```
846
+
847
+ With this configuration, you can run eslint and receive actionable diagnostic information when exports are no longer referenced. If you implement a library, add the file paths that define the variables, types, etc. that your library exports to the `ignoreExports` array so that the rule does not flag intentionally re-exported surfaces.
848
+
685
849
  ### Known Limitations
686
850
 
687
- - The `import/no-unused-modules` rule does not function properly with Native ESM
688
851
  - Some type-aware rules may have performance impacts on very large codebases
689
852
  - Flat config requires ESLint 9.0+ and may not be compatible with older tools
690
853