Skip to content

docs: add FAQ and docs around verbatimModuleSyntax and similar options #10588

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions docs/troubleshooting/faqs/TypeScript.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,29 @@ You can use ESLint to enforce good uses of both ESLint and TypeScript comment di
- The [`@eslint-community/eslint-plugin-eslint-comments`](https://eslint-community.github.io/eslint-plugin-eslint-comments) plugin can enforce general ESLint comment best practices, including requiring descriptions

:::

## How should I handle reports that conflict with [`verbatimModuleSyntax`](https://www.typescriptlang.org/tsconfig/#verbatimModuleSyntax)?

Several TypeScript options impact how imports and exports are handled in your project, including:

- [`allowSyntheticDefaultImports`](https://www.typescriptlang.org/tsconfig/#allowSyntheticDefaultImports)
- [`esModuleInterop`](https://www.typescriptlang.org/tsconfig/#esModuleInterop)
- [`importsNotUsedAsValues`](https://www.typescriptlang.org/tsconfig/#importsNotUsedAsValues)
- [`preserveValueImports`](https://www.typescriptlang.org/tsconfig/#preserveValueImports)
- [`verbatimModuleSyntax`](https://www.typescriptlang.org/tsconfig/#verbatimModuleSyntax)

Additionally, whether one is authoring ES Modules or CommonJS impacts `import`/`export`/`require` semantics.
Some of our rules may not apply or may need special configuration in projects using these options.

For example, the default behavior of [no-require-imports](/rules/no-require-imports) prohibits CommonJS `require` syntax entirely, but `verbatimModuleSyntax` requires it when authoring CommonJS modules.
Therefore, you'll need to configure the rule to permit `import x = require('foo')` syntax.

Known rules that conflict with or require special configuration to be used with `verbatimModuleSyntax` include:

- [consistent-type-imports](/rules/consistent-type-imports#comparison-with-importsnotusedasvalues--verbatimmodulesyntax): should be disabled
- [no-import-type-side-effects](/rules/no-import-type-side-effects): a rule that is only needed at all when using `verbatimModuleSyntax`
- [no-namespace](/rules/no-namespace#when-not-to-use-it): some reports [need to be ignored](/rules/no-namespace#when-not-to-use-it)
- [no-require-imports](/rules/no-require-imports): requires [configuring its `allowAsImport` option](/rules/no-require-imports#allowasimport)

If you are using the [`importsNotUsedAsValues`](https://www.typescriptlang.org/tsconfig/#importsNotUsedAsValues), [`isolatedModules`](https://www.typescriptlang.org/tsconfig/#isolatedModules), and/or [`preserveValueImports`](https://www.typescriptlang.org/tsconfig/#preserveValueImports) TSConfig options, you may need to additionally configure those lint rules as well.
See the rules' documentation for more information.
4 changes: 2 additions & 2 deletions packages/eslint-plugin/docs/rules/consistent-type-imports.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -107,8 +107,8 @@ The rule will **_not_** report any errors in files _that contain decorators_ whe

> See [Blog > Changes to consistent-type-imports when used with legacy decorators and decorator metadata](/blog/changes-to-consistent-type-imports-with-decorators) for more details.

If you are using [type-aware linting](https://typescript-eslint.io/linting/typed-linting) then we will automatically infer your setup from your tsconfig and you should not need to configure anything.
Otherwise you can explicitly tell our tooling to analyze your code as if the compiler option was turned on by setting both [`parserOptions.emitDecoratorMetadata = true`](https://typescript-eslint.io/packages/parser/#emitdecoratormetadata) and [`parserOptions.experimentalDecorators = true`](https://typescript-eslint.io/packages/parser/#experimentaldecorators).
If you are using [type-aware linting](/getting-started/typed-linting) then we will automatically infer your setup from your tsconfig and you should not need to configure anything.
Otherwise you can explicitly tell our tooling to analyze your code as if the compiler option was turned on by setting both [`parserOptions.emitDecoratorMetadata = true`](/packages/parser/#emitdecoratormetadata) and [`parserOptions.experimentalDecorators = true`](/packages/parser/#experimentaldecorators).

## Comparison with `importsNotUsedAsValues` / `verbatimModuleSyntax`

Expand Down
16 changes: 12 additions & 4 deletions packages/eslint-plugin/docs/rules/no-namespace.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -135,15 +135,23 @@ declare module 'foo' {}

## When Not To Use It

If your project was architected before modern modules and namespaces, it may be difficult to migrate off of namespaces.
If your project uses TypeScript's CommonJS export syntax (`export = ...`), you may need to use namespaces in order to export types from your module.
You can learn more about this at:

- [TypeScript#52203](https://github.com/microsoft/TypeScript/pull/52203), the pull request introducing [`verbatimModuleSyntax`](https://www.typescriptlang.org/tsconfig/#verbatimModuleSyntax)
- [TypeScript#60852](https://github.com/microsoft/TypeScript/issues/60852), an issue requesting syntax to export types from a CommonJS module.

If your project uses this syntax, either because it was architected before modern modules and namespaces, or because a module option such as `verbatimModuleSyntax` requires it, it may be difficult to migrate off of namespaces.
In that case you may not be able to use this rule for parts of your project.

You might consider using [ESLint disable comments](https://eslint.org/docs/latest/use/configure/rules#using-configuration-comments-1) for those specific situations instead of completely disabling this rule.

## Further Reading

{/* cspell:disable-next-line */}

- [FAQ: I get errors from the `@typescript-eslint/no-namespace` and/or `no-var` rules about declaring global variables](/troubleshooting/faqs/eslint#i-get-errors-from-the-typescript-eslintno-namespace-andor-no-var-rules-about-declaring-global-variables)
- [Modules](https://www.typescriptlang.org/docs/handbook/modules.html)
- [Namespaces](https://www.typescriptlang.org/docs/handbook/namespaces.html)
- [Namespaces and Modules](https://www.typescriptlang.org/docs/handbook/namespaces-and-modules.html)
- [FAQ: How should I handle reports that conflict with verbatimModuleSyntax?](/troubleshooting/faqs/typescript#how-should-i-handle-reports-that-conflict-with-verbatimmodulesyntax)
- [TypeScript handbook entry on Modules](https://www.typescriptlang.org/docs/handbook/modules.html)
- [TypeScript handbook entry on Namespaces](https://www.typescriptlang.org/docs/handbook/namespaces.html)
- [TypeScript handbook entry on Namespaces and Modules](https://www.typescriptlang.org/docs/handbook/namespaces-and-modules.html)
26 changes: 20 additions & 6 deletions packages/eslint-plugin/docs/rules/no-require-imports.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ import TabItem from '@theme/TabItem';
>
> See **https://typescript-eslint.io/rules/no-require-imports** for documentation.

Prefer the newer ES6-style imports over `require()`.
Depending on your TSConfig settings and whether you're authoring ES Modules or CommonJS, TS may allow both `import` and `require()` to be used, even within a single file.

This rule enforces that you use the newer ES Module `import` syntax over CommonJS `require()`.

## Examples

Expand Down Expand Up @@ -42,7 +44,7 @@ import * as lib3 from 'lib3';

These strings will be compiled into regular expressions with the `u` flag and be used to test against the imported path. A common use case is to allow importing `package.json`. This is because `package.json` commonly lives outside of the TS root directory, so statically importing it would lead to root directory conflicts, especially with `resolveJsonModule` enabled. You can also use it to allow importing any JSON if your environment doesn't support JSON modules, or use it for other cases where `import` statements cannot work.

With `{allow: ['/package\\.json$']}`:
With `{ allow: ['/package\\.json$'] }`:

<Tabs>
<TabItem value="❌ Incorrect">
Expand All @@ -66,9 +68,9 @@ console.log(require('../package.json').version);
{/* insert option description */}

When set to `true`, `import ... = require(...)` declarations won't be reported.
This is useful if you use certain module options that require strict CommonJS interop semantics.
This is beneficial if you use certain module options that require strict CommonJS interop semantics, such as [verbatimModuleSyntax](https://www.typescriptlang.org/tsconfig/#verbatimModuleSyntax).

With `{allowAsImport: true}`:
With `{ allowAsImport: true }`:

<Tabs>
<TabItem value="❌ Incorrect">
Expand All @@ -90,10 +92,22 @@ import foo from 'foo';
</TabItem>
</Tabs>

## Usage with CommonJS

While this rule is primarily intended to promote ES Module syntax, it still makes sense to enable this rule when authoring CommonJS modules.

If you prefer to use TypeScript's built-in `import ... from ...` ES Module syntax, which is transformed to `require()` calls during transpilation when outputting CommonJS, you can use the rule's default behavior.

If, instead, you prefer to use `require()` syntax, we recommend you use this rule with [`allowAsImport`](#allowAsImport) enabled.
That way, you still enforce usage of `import ... = require(...)` rather than bare `require()` calls, which are not statically analyzed by TypeScript.
We don't directly a way to _prohibit_ ES Module syntax from being used; consider instead using TypeScript's [`verbatimModuleSyntax`](https://www.typescriptlang.org/tsconfig/#verbatimModuleSyntax) option if you find yourself in a situation where you would want this.

## When Not To Use It

If your project frequently uses older CommonJS `require`s, then this rule might not be applicable to you.
If only a subset of your project uses `require`s then you might consider using [ESLint disable comments](https://eslint.org/docs/latest/use/configure/rules#using-configuration-comments-1) for those specific situations instead of completely disabling this rule.
If you are authoring CommonJS modules _and_ your project frequently uses dynamic `require`s, then this rule might not be applicable to you.
Otherwise the `allowAsImport` option probably suits your needs.

If only a subset of your project uses dynamic `require`s then you might consider using [ESLint disable comments](https://eslint.org/docs/latest/use/configure/rules#using-configuration-comments-1) for those specific situations instead of completely disabling this rule.

## Related To

Expand Down
Loading