# Typescript Eslint
> typescript-eslint
---
# TypeScript ESLint Documentation
# Source: https://raw.githubusercontent.com/typescript-eslint/typescript-eslint/main/README.md
# Path: README.md
typescript-eslint
Monorepo for typescript-eslint: powerful static analysis for JavaScript and TypeScript
👇
See typescript-eslint.io for documentation on the latest released version.
See main--typescript-eslint.netlify.app for documentation on the latest canary release.
👆
## Code Contributors
This project exists thanks to the awesome people who contribute code and documentation:
🙏 An extra special thanks goes out to the wonderful people listed in .
## Financial Contributors
In addition to submitting code and documentation updates, you can help us sustain our community by becoming a financial contributor [[Click here to contribute - every little bit helps!](https://opencollective.com/typescript-eslint/contribute)]
## License
typescript-eslint inherits is licensed under a permissive MIT license.
---
# TypeScript ESLint Documentation
# Source: https://raw.githubusercontent.com/typescript-eslint/typescript-eslint/main/docs/Contributing.mdx
# Path: docs/Contributing.mdx
---
id: contributing
title: Contributing
---
Thank you for your interest in contributing to typescript-eslint! 💜
Although typescript-eslint's packages are already downloaded millions of times per month and power high profile projects across our industry, this is a 100% community-driven project.
From the second you install one of the packages from this monorepo, you are a part of that community.
So, from the bottom of our hearts, _thank you_ 💕.
## Getting Started
Please read our [Code of Conduct](https://github.com/typescript-eslint/typescript-eslint/blob/main/CODE_OF_CONDUCT.md) first.
If you're new to open source, you may also find the [How to Contribute to Open Source](https://opensource.guide/how-to-contribute) guide from https://opensource.guide useful.
## Next Steps
1. [Finding or opening an issue](./contributing/Issues.mdx): In the issue tab, finding or creating an issue to work on.
2. [Setting up a local environment](./contributing/Local_Development.mdx): Learning how to set up the local environment to start development.
3. [Making a PR](./contributing/Pull_Requests.mdx): Sending in your changes to resolve an accepted issue.
---
# TypeScript ESLint Documentation
# Source: https://raw.githubusercontent.com/typescript-eslint/typescript-eslint/main/docs/Developers.mdx
# Path: docs/Developers.mdx
---
id: developers
title: Developers
---
These are the developer guides to working with the typescript-eslint tooling.
It's intended for use by third-parties who want to use our tools to build great things.
:::info Welcome!
If you're reading this as a new developer: welcome to the community!
We're happy to have you! ❤️🔥
:::
---
# TypeScript ESLint Documentation
# Source: https://raw.githubusercontent.com/typescript-eslint/typescript-eslint/main/docs/Maintenance.mdx
# Path: docs/Maintenance.mdx
---
id: maintenance
sidebar_label: Maintenance Guide
title: Maintenance Guide
---
This is the maintainers guide to working on typescript-eslint.
It's intended for use by contributors who have been given access to at least triage issues and pull requests.
We keep it in the open for visibility into our processes.
:::info Welcome!
If you're reading this as a new maintainer: welcome!
We're happy to have you! ❤️🔥
:::
## Governance
We follow a loose governance model that covers roles on the maintenance team and their associated responsibilities.
We see a few major benefits from doing so:
- We want it to be clear how & why we do the things we do _(especially around compensation and expectations around roles)_
- We want community input to make sure we're doing things the right way & focusing on truly useful improvements
- As we add to the processes over time, it'll be easier to make those changes clear & reviewable by everyone
The following pages are a rough "v1.x" of our governance.
We do our best to roughly adhere to this model - though at times we may shortcut tasks if there is no downside in doing so.
### Changes to Governance
Any changes to this document will be posted for open discussion on the [typescript-eslint GitHub Discussions](https://github.com/typescript-eslint/typescript-eslint/discussions) and kept open for at least one month.
The discussion will be shared at the beginning, middle, and end of that month on Discord and all our social media accounts.
## Providing Feedback
We're always receptive to suggestions on how to improve our processes!
For general feedback, we'd suggest posting in the [`#development` channel on Discord](https://discord.com/channels/1026804805894672454/1088474511759917106).
We can help you turn that into a GitHub discussion.
:::note
Please be kind: open source governance is an unsolved challenge.
We might not know what impractical or non-ideal things we're doing.
If there's anything sensitive you don't feel comfortable talking about in public, you can always DM or email one of the maintainers privately.
:::
---
# TypeScript ESLint Documentation
# Source: https://raw.githubusercontent.com/typescript-eslint/typescript-eslint/main/docs/Packages.mdx
# Path: docs/Packages.mdx
---
id: packages
title: Packages
---
The `@typescript-eslint/*` packages are all stored in [our GitHub monorepo](https://github.com/typescript-eslint/typescript-eslint).
The monorepo is built and released with [Nx](https://nx.dev).
## `typescript-eslint`
As of v7 and ESLint 9, most users should be using the **[`typescript-eslint`](./packages/TypeScript_ESLint.mdx)** package.
It exports configurations for ESLint and brings along the corresponding versions of other packages as dependencies.
:::tip
See [Getting Started](./getting-started/Quickstart.mdx) for guidance on setting up typescript-eslint on a project.
:::
## Other Packages
Each page in this section corresponds to a package we intentionally expose to users.
Alongside [`typescript-eslint`](./packages/TypeScript_ESLint.mdx), they are:
- [`@typescript-eslint/eslint-plugin`](./packages/ESLint_Plugin.mdx): An ESLint plugin which provides lint rules for TypeScript codebases.
- [`@typescript-eslint/eslint-plugin-tslint`](./packages/ESLint_Plugin_TSLint.mdx): An ESLint plugin that allows running TSLint rules within ESLint to help you migrate from TSLint to ESLint.
- [`@typescript-eslint/parser`](./packages/Parser.mdx): An ESLint parser which allows for ESLint to lint TypeScript source code.
- [`@typescript-eslint/rule-tester`](./packages/Rule_Tester.mdx): A utility for testing ESLint rules.
- [`@typescript-eslint/scope-manager`](./packages/Scope_Manager.mdx): A fork of [`eslint-scope`](https://github.com/eslint/eslint-scope), enhanced to support TypeScript functionality.
- [`@typescript-eslint/typescript-estree`](./packages/TypeScript_ESTree.mdx): The underlying code used by [`@typescript-eslint/parser`](./packages/Parser.mdx) that converts TypeScript source code into an [ESTree](https://github.com/estree/estree)-compatible form.
- [`@typescript-eslint/utils`](./packages/Utils.mdx): Utilities for working with TypeScript + ESLint together.
---
# TypeScript ESLint Documentation
# Source: https://raw.githubusercontent.com/typescript-eslint/typescript-eslint/main/docs/contributing/Discussions.mdx
# Path: docs/contributing/Discussions.mdx
---
id: discussions
title: Discussions
---
Most proposals in the typescript-eslint repository happen in [GitHub Issues](https://docs.github.com/issues).
We generally try to keep conversations inside issues for their discoverability and ability to be linked to [GitHub Pull Requests](https://docs.github.com/pull-requests).
We have [GitHub Discussions](https://docs.github.com/discussions) enabled to enable three kinds of deeper, threaded conversations:
- **Community Feedback**: Questions from the maintainer team that should be raised to the broader community
- **RFCs (Requests For Comments)**: Formalized proposals for larger changes that should be discussed before turned into issues
- **Technical Discussions**: Deeper questions about typescript-eslint's architecture and/or APIs
Before filing a Discussion, search the issue tracker for any related conversations.
Link to them in the Discussion, along with a detailed description of what you'd like to discuss.
:::tip
For change proposals that match an [existing issue format](https://github.com/typescript-eslint/typescript-eslint/issues/new/choose), keep to filing issues.
Most don't need to be moved to this separate format.
We can always move an issue to a discussion if it becomes unexpectedly deep.
:::
:::caution
Please don't use Discussions as a support forum.
See [Contributing > Issues > Questions and Support Requests](./Issues.mdx#questions-and-support-requests).
:::
---
# TypeScript ESLint Documentation
# Source: https://raw.githubusercontent.com/typescript-eslint/typescript-eslint/main/docs/contributing/Issues.mdx
# Path: docs/contributing/Issues.mdx
---
id: issues
title: Issues
---
So you've got a bug report, documentation request, or feature suggestion?
Great!
Please do:
- Make sure you're using the [latest version of our packages](https://github.com/typescript-eslint/typescript-eslint/releases)
- Search [all opened and closed issues](https://github.com/typescript-eslint/typescript-eslint/issues?q=is%3Aissue+) to make sure your issue wouldn't be a duplicate
- Fill out the [appropriate issue template](https://github.com/typescript-eslint/typescript-eslint/issues/new/choose) completely
- Provide as much information as you can
## Commenting
Please do comment on any open issue if you have more information that would be useful.
Please don't:
- Leave useless comments such as _"+1"_ or _"when's this getting fixed?"_ that only act as spam
- If you have nothing to add but enthusiasm and joy, add a reaction such as 👍
- One exception: if an issue has been blocked on a question to a maintainer for 3 or more months, please ping us - we probably lost track of it
- Bring up unrelated topics in existing issues: instead, file a new issue
- Comment on closed PRs: instead, [file a new issue](#raising-issues)
- Comment on commits directly, as those comments are not searchable: instead, file a new issue
### Issue Claiming
We don't use any kind of issue claiming system.
We've found in the past that they result in accidental ["licked cookie"](https://devblogs.microsoft.com/oldnewthing/20091201-00/?p=15843) situations where contributors claim an issue but run out of time or energy trying before sending a PR.
If an issue has been marked as `accepting prs` and an open PR does not exist, feel free to send a PR.
You don't need to ask for permission.
## Finding Issues
Consider searching through:
1. [Unassigned user-facing marked as `accepting prs` and `good first issue`](https://github.com/typescript-eslint/typescript-eslint/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22+label%3A%22accepting+prs%22+-label%3A%22repo+maintenance%22+no%3Aassignee): to find issues marked as good for a first-timer
2. [Unassigned user-facing marked as `accepting prs` without `good first issue`](https://github.com/typescript-eslint/typescript-eslint/issues?q=is%3Aopen+is%3Aissue+label%3A%22accepting+prs%22+-label%3A%22good+first+issue%22+-label%3A%22repo+maintenance%22+no%3Aassignee): once you've finished a few issues, to find more intermediate-level issues
## "Evaluating Community Engagement"
The typescript-eslint project has limited maintenance bandwidth and cannot commit to every potentially valid issue.
It can be difficult to tell if some issues' impacts would be worth taking bandwidth away from other, higher-impact issues.
For those issues, we will:
1. Add an `evaluating community engagement` label to indicate the issue is under review
2. Wait at least 3-6 months
3. Either accept or decline the issue, depending on how much engagement the issue receives
If your issue is marked as `evaluating community engagement`, we encourage you to:
- Socialize the issue online to find other users who are in favor of it
- Try out the proposed changes in your own projects
- If the issue is for a new lint rule, consider using our [Building ESLint Plugins documentation](https://typescript-eslint.io/developers/eslint-plugins) to create a standalone plugin users can try
See [Maintenance > Issues > Community Engagement Evaluation](https://typescript-eslint.io/maintenance/issues/#community-engagement-evaluation) for documentation on our corresponding maintenance practices.
## Questions and Support Requests
The issue tracker is not an appropriate place for questions or support requests.
You can instead:
- Ask in our [Discord server](https://discord.gg/FSxKq8Tdyg)'s `#help` server
- Ask a question on [StackOverflow](https://stackoverflow.com/questions/tagged/typescript-eslint 'StackOverflow questions tagged with typescript-eslint') using the `typescript-eslint` tag
- Publicly tag [@typescript-eslint.io on Bluesky](https://bsky.app/profile/typescript-eslint.io) or [@tseslint on Mastodon](https://fosstodon.org/@tseslint)
> Note that requests to add documentation _are_ allowed, even encouraged! 📝
---
:::note Appreciation Note
Thanks for reading through this file in full!
Please include your favorite emoji at the bottom of your issue to hint to us that you did in fact read this file.
💖 is a good starter if you're not sure which to use.
:::
---
# TypeScript ESLint Documentation
# Source: https://raw.githubusercontent.com/typescript-eslint/typescript-eslint/main/docs/contributing/Local_Development.mdx
# Path: docs/contributing/Local_Development.mdx
---
id: local-development
title: Local Development
---
Thank you for your interest in developing on typescript-eslint! ❤️🔥
> See [Contributing](../Contributing.mdx) and [Issues](./Issues.mdx) for details on our general contribution flows.
## Setup
After [forking the repo from GitHub](https://help.github.com/articles/fork-a-repo) and [installing Yarn](https://yarnpkg.com):
```shell
git clone https://github.com//typescript-eslint
cd typescript-eslint
yarn
```
You can see which version of `yarn` we use by checking the `packageManager` field in the root `package.json`.
Postinstall scripts will then fully build your repository locally with (`yarn build`).
At this point, you're ready to develop! 🚀
## Builds
You can run `yarn build` in the root to build all packages, or in any package to build just that package.
Keep in mind that packages generally depend on each other's built outputs, and you'll need to `yarn build` dependents for their consumers to receive any new local changes.
For example, if you make a change within `scope-manager` and want to use it in `eslint-plugin`, you'll need to `yarn build` either from the root or within `packages/scope-manager`.
## Validating Changes
The following checks are all run on pull requests automatically.
You can also perform them locally.
> See [Contributing > Pull Requests](./Pull_Requests.mdx) for more information on pull requests.
### Formatting
We use [Prettier](https://prettier.io) to auto-format code.
A Git pre-commit hook should apply it to all committed changes.
Alternately, you can run `yarn format` in any package or in the root.
### Linting
All code changes must pass ESLint.
You can run `yarn lint` in any package or in the root.
### Proofreading
Changes must pass two linters for documentation and naming, the commands for which may be run from the root:
- `yarn check-spelling`: [CSpell](https://cspell.org), for all code
- `yarn lint-markdown`: [Markdownlint](https://github.com/DavidAnson/markdownlint), for Markdown documentation
### Tests
All code changes should ideally be unit tested if possible.
You can run `yarn test` in any package to run its tests.
Oftentimes, you will only want to run one specific test related to the bug you are fixing or the feature you are implementing. To do this, you can add `only: true` to the test object definition. (Doing this will cause a new lint error for `eslint-plugin/no-only-tests`, but just ignore it while you work. The lint rule is only there so that you remember to delete the `only: true` once it comes time to make a pull request.)
> The repository has [Visual Studio Code launch tasks](https://code.visualstudio.com/docs/editor/tasks) that allow for [visually debugging tests](https://code.visualstudio.com/docs/editor/debugging).
### Type Checking
All code should pass TypeScript type checking.
You can run `yarn typecheck` in any package or in the root to run `tsc`.
> Run `yarn typecheck -w` to start `tsc` in watch mode.
## Rule Development
Some portions of this repository are generated by manually running scripts that read from rule files.
If you modify rules, you may need to run either or both of:
- `yarn generate-configs` from root: to regenerate [shared configs](../users/Shared_Configurations.mdx)
- `yarn test docs -u` from `packages/eslint-plugin`: to regenerate snapshots based on rule docs and options
## Website Development
Our interactive documentation website is built with [Docusaurus](https://docusaurus.io).
Running `yarn start` from either the root or `packages/website` will start a local dev server on `localhost:3000`.
> The `website` package relies on other packages being built.
> We recommend running `yarn build` from the root before `yarn start`.
---
# TypeScript ESLint Documentation
# Source: https://raw.githubusercontent.com/typescript-eslint/typescript-eslint/main/docs/contributing/Pull_Requests.mdx
# Path: docs/contributing/Pull_Requests.mdx
---
id: pull-requests
title: Pull Requests
---
> See [Local Development](./Local_Development.mdx) for details on how to get started developing locally.
So you've got changes locally that address an issue?
Fantastic!
Please do:
- Only send pull requests that resolve [open, unassigned issues marked as `accepting prs`](https://github.com/typescript-eslint/typescript-eslint/issues?q=is%3Aissue+is%3Aopen+label%3A%22accepting+prs%22+no%3Aassignee)
- One exception: extremely minor documentation typos
- Fill out the pull request template in full
- Validate your changes per [Development > Validating Changes](./Local_Development.mdx#validating-changes) before un-[drafting your PR](https://github.blog/2019-02-14-introducing-draft-pull-requests)
Please don't:
- Force push after opening a PR
- Reasoning: GitHub is not able to track changes across force pushes, which makes it take longer for us to perform incremental reviews
- Comment on an existing PR asking for updates
- Reasoning: Your PR hasn't been forgotten! The volunteer maintainers have limited time to work on the project, and they will get to it as soon as they are able.
- One exception: if a PR has been blocked on a question to a maintainer for 3 or more months, please ping us - we probably lost track of it.
- Comment on a closed PR
- Reasoning: It is much easier for maintainers to not lose track of things if they are posted as issues. If you think there's a bug in typescript-eslint, the right way to ask is to [file a new issue](https://github.com/typescript-eslint/typescript-eslint/issues/new/choose). The issue templates include helpful & necessary practices such as making sure you're on the latest version of all our packages. You can provide the link to the relevant PR to add more context.
## Testing Changes
### Code Coverage
We aim for 100% code coverage in all PRs when possible, except in the `website/` package.
Coverage reports are generated locally whenever `yarn test` is run.
The `codecov` bot also comments on each PR with its percentage, as well as links to the line-by-line coverage of each file touched by the PR.
### Granular Unit Tests
Most tests in most packages are set up as small, self-contained unit tests.
We generally prefer that to keep tests and their failure reports granular.
For rule tests we recommend, when reasonable:
- Including both `valid` and `invalid` code changes in most PRs that affect rule behavior
- Limiting to one error per `invalid` case
### AST Testing
AST tests belong in the `ast-spec` package, within `fixtures/` subfolders alongside the AST declarations. Each test has its own `/` folder, containing a `fixture.ts` file defining the test, and a `snapshots/` subfolder. Happy-path test folders are stored directly under `fixtures/`; error-path test folders go under `fixtures/_errors/`. You can check out the [`ClassDeclaration` fixtures folder](https://github.com/typescript-eslint/typescript-eslint/tree/main/packages/ast-spec/src/declaration/ClassDeclaration/fixtures) for an example of both happy-path and unhappy-path test folders.
## Raising the PR
Once your changes are ready, you can raise a PR! 🙌
The title of your PR should match the following format:
```text
():
```
You can find more samples of good past PR titles in [recent commits to `main`](https://github.com/typescript-eslint/typescript-eslint/commits/main):
- `fix(scope-manager): correct handling for class static blocks`
- `docs: fix links to getting started in README.md`
Within the body of your PR, make sure you reference the issue that you have worked on, as well as pointing out anything of note you wish us to look at during our review.
> We do not care about the number, or style of commits in your history, because we squash merge every PR into `main`.
> Feel free to commit in whatever style you feel comfortable with.
> Tip: Send the PR from a branch other than `main`.
> See GitHub's [Proposing Changes docs](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests) for more information.
### type
Must be one of the following:
{/* Keep this synchronized with /.github/workflows/pr-title-validation.yml */}
- `docs` - if you only change documentation, and not shipped code
- `feat` - for any new functionality additions
- `fix` - for any bug fixes that don't add new functionality
- `test` - if you only change tests, and not shipped code
- `chore` - anything else
### package
The name of the package you have made changes within, (e.g. `eslint-plugin`, `parser`, `typescript-estree`).
If you make significant changes across multiple packages, you can omit this (e.g.
`feat: foo bar`).
### short description
A succinct title for the PR.
## Addressing Feedback and Beyond
With your PR raised and the CI passing, your PR will [wait in the queue to be reviewed](https://github.com/typescript-eslint/typescript-eslint/pulls?q=is%3Apr+is%3Aopen+sort%3Acreated-asc+-label%3A%22breaking+change%22+-label%3A%22awaiting+response%22+-label%3A%221+approval%22+-label%3A%22DO+NOT+MERGE%22+status%3Asuccess).
We generally review PRs oldest to newest, unless we consider a newer PR higher priority (e.g. if it's a bug fix).
Once we have reviewed your PR, we will provide any feedback that needs addressing.
If you feel a requested change is wrong, don't be afraid to discuss with us in the comments.
Please post comments as [line comments](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/reviewing-changes-in-pull-requests/commenting-on-a-pull-request#adding-line-comments-to-a-pull-request) when possible, so that they can be threaded.
You can [resolve conversations](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/reviewing-changes-in-pull-requests/commenting-on-a-pull-request#resolving-conversations) on your own when you feel they're resolved - no need to comment explicitly and/or wait for a maintainer.
Once you've addressed all our feedback by making code changes and/or started a followup discussion, [re-request review](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/reviewing-changes-in-pull-requests/about-pull-request-reviews#re-requesting-a-review) from each maintainer whose feedback you addressed.
Once the feedback is addressed, and the PR is approved, we'll ensure the branch is up to date with `main`, and merge it for you.
### Updating Over Time
You generally don't need to keep merging commits from `main` into your PR branch.
If you see merge conflicts or other intersections that worry you, then you can preemptively - but that's optional.
If we think merge conflicts need to be resolved in order to merge and/or review a PR, we might do that for you as a courtesy _if_ we have time.
If not, we may ask you to.
## Asking Questions
If you need help and/or have a question, posting a comment in the PR is a great way to do so.
There's no need to tag anybody individually.
One of us will drop by and help when we can.
---
:::note Appreciation Note
Thanks for reading through this file in full!
Please include your favorite emoji at the bottom of your pull request to hint to us that you did in fact read this file.
💖 is a good starter if you're not sure which to use.
:::
---
# TypeScript ESLint Documentation
# Source: https://raw.githubusercontent.com/typescript-eslint/typescript-eslint/main/docs/contributing/local-development/Local_Linking.mdx
# Path: docs/contributing/local-development/Local_Linking.mdx
---
id: local-linking
title: Local Linking
---
It can sometimes be useful to try out your local `typescript-eslint` repository's changes in another local ("downstream") repository.
The general strategy to do so is:
1. [Global linking](#global-linking): Use your package manager's global link command to make `@typescript-eslint/*` packages available as global symlinks.
2. [Repository linking](#repository-linking): Use your package manager's link command to reference those global symlinks in the local downstream repository.
3. [Trying rules](#trying-rules): Test your local rules and plugins by enabling them in the local downstream repository.
:::tip
Before linking a repository, make sure it's gone through the steps in [Getting Started](../../getting-started/Quickstart.mdx) to be able to use typescript-eslint rules.
:::
## Global Linking
To make all `@typescript-eslint/*` packages available globally, run this command from your `typescript-eslint` repository root:
```shell
for package in ./packages/*; do
cd $package
# Insert your package manager's global link command here
cd ../..
done
```
The command to put instead of that `#` comment, depends on the local downstream repository's package manager:
- [npm](https://docs.npmjs.com/cli/v9/commands/npm-link 'npm link docs'): `npm link`
- [pnpm](https://pnpm.io/cli/link 'pnpm link docs'): `pnpm link --global`
- [Yarn v1 / classic](https://classic.yarnpkg.com/lang/en/docs/cli/link/ 'Yarn v1 / classic docs'): `yarn link`
- [Yarn v2 / v3 / berry](https://yarnpkg.com/cli/link 'Yarn v2 / v3 / berry docs'): _skip this step altogether_
Additionally, if you haven't yet built the typescript-eslint repository, do so now:
```shell
yarn build
```
## Repository Linking
Now that the `@typescript-eslint/*` packages are built and available locally, you can link to them in the local downstream repository.
Run that repository's package manager's link command for any `@typescript-eslint/*` packages that repository depends on:
- npm: `npm link @typescript-eslint/eslint-plugin @typescript-eslint/parser`
- pnpm: `pnpm link @typescript-eslint/eslint-plugin @typescript-eslint/parser --global`
- Yarn v1 / classic: `yarn link @typescript-eslint/eslint-plugin @typescript-eslint/parser`
- Yarn v2 / v3 / berry: `yarn link /path/to/your/typescript-eslint/packages/eslint-plugin /path/to/your/typescript-eslint/packages/parser`
- This will add a `resolutions` entry for each package in the local downstream repository's `package.json`
Now, you should be able to run ESLint in the local downstream repository as you normally would, and have it reference the local typescript-eslint package.
:::tip
To check that the local package is being used, consider adding a `console.log("Hello, world!");` to a file such as `./packages/eslint-plugin/dist/index.js` and making sure that log appears when linting the local downstream repository.
:::
## Trying Rules
Now that you've linked the `@typescript-eslint/*` packages with your local downstream repository, the next step would be to include the rule on the local repository ESLint configuration file, e.g:
```json title=".eslintrc.json"
{
"rules": {
"@typescript-eslint/your-awesome-rule": "error"
}
// ...
}
```
After that, you need to run your repository's `lint` script and your changes should be reflected on the project.
:::note
Changes to `@typescript-eslint/` packages will not be reflected inside your linked repository until they're built locally.
To re-build all packages, run `yarn build` from the root.
To start a watch mode builder on just the ESLint plugin, run `yarn build --watch` from `./packages/eslint-plugin`.
:::
## Troubleshooting
### Packages Not Found (`Cannot find module`)
If a local `@typescript-eslint/*` package has a dependency not present in the published npm version, linting in the local downstream repository may see a different error:
```plaintext
Error: Failed to load parser '@typescript-eslint/parser' declared in '.eslintrc.js': Cannot find module 'ts-api-utils'
Require stack:
- /repos/typescript-eslint/packages/typescript-estree/dist/convert-comments.js
```
In this case, you can manually install any missing packages in the local downstream repository as dev dependencies (`--save-dev`).
```shell
yarn add ts-api-utils -D
```
### Rules Not Found (`Definition for rule ... was not found`)
Packages need to be built.
First try re-running `yarn build` from the typescript-eslint repository root.
If you're adding new rules, you'll need to also modify [`packages/eslint-plugin/src/rules/index.ts`](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/src/rules/index.ts) to export the rule object, then re-build.
If you're modifying preset configurations, you'll also need to run `yarn generate-configs`, then re-build.
### Yarn Link Failures (`Cannot link ... conflicts with parent dependency`)
Yarn v2 / v3 / berry can be strict about conflicting dependencies.
You may see errors about conflicting versions when running `yarn` to install in the local downstream repository:
```plaintext
$ yarn
➤ YN0000: ┌ Resolution step
➤ YN0000: └ Completed
➤ YN0000: ┌ Fetch step
➤ YN0000: └ Completed
➤ YN0000: ┌ Link step
➤ YN0071: │ Cannot link @typescript-eslint/parser into eslint-plugin-import@npm:2.27.5 [6d590] dependency debug@npm:4.3.4 [531b6] conflicts with parent dependency debug@npm:3.2.7 [65bed]
➤ YN0071: │ Cannot link @typescript-eslint/parser into eslint-module-utils@npm:2.8.0 [0b7fa] dependency debug@npm:4.3.4 [531b6] conflicts with parent dependency debug@npm:3.2.7 [65bed]
➤ YN0000: └ Completed in 0s 370ms
➤ YN0000: Failed with errors in 0s 643ms
```
To resolve this, you can add a manual entry to the `resolutions` field in the local downstream repository's `package.json` for each failing package.
Use the largest major version referenced in the Yarn errors.
```json
{
"resolutions": {
"@typescript-eslint/eslint-plugin": "portal:/path/to/your/typescript-eslint/packages/eslint-plugin",
"@typescript-eslint/parser": "portal:/path/to/your/typescript-eslint/packages/parser",
"debug": "4"
}
}
```
Re-running `yarn` should succeed.
---
# TypeScript ESLint Documentation
# Source: https://raw.githubusercontent.com/typescript-eslint/typescript-eslint/main/docs/developers/Custom_Rules.mdx
# Path: docs/developers/Custom_Rules.mdx
---
id: custom-rules
sidebar_label: Building Custom Rules
title: Custom Rules
---
:::important
This page describes how to write your own custom ESLint rules using typescript-eslint.
You should be familiar with [ESLint's developer guide](https://eslint.org/docs/developer-guide) and [ASTs](/blog/asts-and-typescript-eslint) before writing custom rules.
:::
As long as you are using `@typescript-eslint/parser` as the `parser` in your ESLint configuration, custom ESLint rules generally work the same way for JavaScript and TypeScript code.
The main four changes to custom rules writing are:
- [Utils Package](#utils-package): we recommend using `@typescript-eslint/utils` to create custom rules
- [AST Extensions](#ast-extensions): targeting TypeScript-specific syntax in your rule selectors
- [Typed Rules](#typed-rules): using the TypeScript type checker to inform rule logic
- [Testing](#testing): using `@typescript-eslint/rule-tester`'s `RuleTester` instead of ESLint core's
## Utils Package
The [`@typescript-eslint/utils`](../packages/Utils.mdx) package acts as a replacement package for `eslint` that exports all the same objects and types, but with typescript-eslint support.
It also exports common utility functions and constants most custom typescript-eslint rules tend to use.
:::caution
`@types/eslint` types are based on `@types/estree` and do not recognize typescript-eslint nodes and properties.
You should generally not need to import from `eslint` when writing custom typescript-eslint rules in TypeScript.
:::
### `RuleCreator`
The recommended way to create custom ESLint rules that make use of typescript-eslint features and/or syntax is with the `ESLintUtils.RuleCreator` function exported by `@typescript-eslint/utils`.
It takes in a function that transforms a rule name into its documentation URL, then returns a function that takes in a rule module object.
`RuleCreator` will infer the allowed message IDs the rule is allowed to emit from the provided `meta.messages` object.
This rule bans function declarations that start with a lower-case letter:
```ts
import { ESLintUtils } from '@typescript-eslint/utils';
const createRule = ESLintUtils.RuleCreator(
name => `https://example.com/rule/${name}`,
);
// Type: RuleModule<"uppercase", ...>
export const rule = createRule({
create(context) {
return {
FunctionDeclaration(node) {
if (node.id != null) {
if (/^[a-z]/.test(node.id.name)) {
context.report({
messageId: 'uppercase',
node: node.id,
});
}
}
},
};
},
name: 'uppercase-first-declarations',
meta: {
docs: {
description:
'Function declaration names should start with an upper-case letter.',
},
messages: {
uppercase: 'Start this name with an upper-case letter.',
},
type: 'suggestion',
schema: [],
},
defaultOptions: [],
});
```
`RuleCreator` rule creator functions return rules typed as the `RuleModule` interface exported by `@typescript-eslint/utils`.
It allows specifying generics for:
- `MessageIds`: a union of string literal message IDs that may be reported
- `Options`: what options users may configure for the rule (by default, `[]`)
If the rule is able to take in rule options, declare them as a tuple type containing a single object of rule options:
```ts
import { ESLintUtils } from '@typescript-eslint/utils';
type MessageIds = 'lowercase' | 'uppercase';
type Options = [
{
preferredCase?: 'lower' | 'upper';
},
];
// Type: RuleModule
export const rule = createRule({
// ...
});
```
#### Extra Rule Docs Types
By default, rule `meta.docs` is allowed to contain only `description` and `url` as described in [ESLint's Custom Rules > Rule Structure docs](https://eslint.org/docs/latest/extend/custom-rules#rule-structure).
Additional docs properties may be added as a type argument to `ESLintUtils.RuleCreator`:
```ts
interface MyPluginDocs {
recommended: boolean;
}
const createRule = ESLintUtils.RuleCreator(
name => `https://example.com/rule/${name}`,
);
createRule({
// ...
meta: {
docs: {
description: '...',
recommended: true,
},
// ...
},
});
```
### Undocumented Rules
Although it is generally not recommended to create custom rules without documentation, if you are sure you want to do this you can use the `ESLintUtils.RuleCreator.withoutDocs` function to directly create a rule.
It applies the same type inference as the `createRule`s above without enforcing a documentation URL.
```ts
import { ESLintUtils } from '@typescript-eslint/utils';
export const rule = ESLintUtils.RuleCreator.withoutDocs({
create(context) {
// ...
},
meta: {
// ...
},
});
```
:::caution
We recommend any custom ESLint rule include a descriptive error message and link to informative documentation.
:::
## Handling rule options
ESLint rules can take options. When handling options, you will need to add information in at most three places:
- The `Options` generic type argument to `RuleCreator`, where you declare the type of the options
- The `meta.schema` property, where you add a JSON schema describing the options shape
- The `defaultOptions` property, where you add the default options value
```ts
type MessageIds = 'lowercase' | 'uppercase';
type Options = [
{
preferredCase: 'lower' | 'upper';
},
];
export const rule = createRule({
meta: {
// ...
schema: [
{
type: 'object',
properties: {
preferredCase: {
type: 'string',
enum: ['lower', 'upper'],
},
},
additionalProperties: false,
},
],
},
defaultOptions: [
{
preferredCase: 'lower',
},
],
create(context, options) {
if (options[0].preferredCase === 'lower') {
// ...
}
},
});
```
:::warning
When reading the options, use the second parameter of the `create` function, not `context.options` from the first parameter. The first is created by ESLint and does not have the default options applied.
:::
## AST Extensions
`@typescript-eslint/estree` creates AST nodes for TypeScript syntax with names that begin with `TS`, such as `TSInterfaceDeclaration` and `TSTypeAnnotation`.
These nodes are treated just like any other AST node.
You can query for them in your rule selectors.
This version of the above rule instead bans interface declaration names that start with a lower-case letter:
```ts
import { ESLintUtils } from '@typescript-eslint/utils';
export const rule = createRule({
create(context) {
return {
TSInterfaceDeclaration(node) {
if (/^[a-z]/.test(node.id.name)) {
// ...
}
},
};
},
// ...
});
```
### Node Types
TypeScript types for nodes exist in a `TSESTree` namespace exported by `@typescript-eslint/utils`.
The above rule body could be better written in TypeScript with a type annotation on the `node`:
An `AST_NODE_TYPES` enum is exported as well to hold the values for AST node `type` properties.
`TSESTree.Node` is available as union type that uses its `type` member as a discriminant.
For example, checking `node.type` can narrow down the type of the `node`:
```ts
import { AST_NODE_TYPES, TSESTree } from '@typescript-eslint/utils';
export function describeNode(node: TSESTree.Node): string {
switch (node.type) {
case AST_NODE_TYPES.ArrayExpression:
return `Array containing ${node.elements.map(describeNode).join(', ')}`;
case AST_NODE_TYPES.Literal:
return `Literal value ${node.raw}`;
default:
return '🤷';
}
}
```
### Explicit Node Types
Rule queries that use more features of [esquery](https://github.com/estools/esquery) such as targeting multiple node types may not be able to infer the type of the `node`.
In that case, it is best to add an explicit type declaration.
This rule snippet targets name nodes of both function and interface declarations:
```ts
import { TSESTree } from '@typescript-eslint/utils';
export const rule = createRule({
create(context) {
return {
'FunctionDeclaration, TSInterfaceDeclaration'(
node: TSESTree.FunctionDeclaration | TSESTree.TSInterfaceDeclaration,
) {
if (/^[a-z]/.test(node.id.name)) {
// ...
}
},
};
},
// ...
});
```
## Typed Rules
:::tip
Read TypeScript's [Compiler APIs > Type Checker APIs](https://github.com/microsoft/TypeScript/wiki/Using-the-Compiler-API#type-checker-apis) for how to use a program's type checker.
:::
The biggest addition typescript-eslint brings to ESLint rules is the ability to use TypeScript's type checker APIs.
`@typescript-eslint/utils` exports an `ESLintUtils` namespace containing a `getParserServices` function that takes in an ESLint context and returns a `services` object.
That `services` object contains:
- `program`: A full TypeScript `ts.Program` object if type checking is enabled, or `null` otherwise
- `esTreeNodeToTSNodeMap`: Map of `@typescript-eslint/estree` `TSESTree.Node` nodes to their TypeScript `ts.Node` equivalents
- `tsNodeToESTreeNodeMap`: Map of TypeScript `ts.Node` nodes to their `@typescript-eslint/estree` `TSESTree.Node` equivalents
If type checking is enabled, that `services` object additionally contains:
- `getTypeAtLocation`: Wraps the type checker function, with a `TSESTree.Node` parameter instead of a `ts.Node`
- `getSymbolAtLocation`: Wraps the type checker function, with a `TSESTree.Node` parameter instead of a `ts.Node`
Those additional objects internally map from ESTree nodes to their TypeScript equivalents, then call to the TypeScript program.
By using the TypeScript program from the parser services, rules are able to ask TypeScript for full type information on those nodes.
This rule bans for-of looping over an enum by using the TypeScript type checker via typescript-eslint's services:
```ts
import { ESLintUtils } from '@typescript-eslint/utils';
import * as ts from 'typescript';
export const rule = createRule({
create(context) {
return {
ForOfStatement(node) {
// 1. Grab the parser services for the rule
const services = ESLintUtils.getParserServices(context);
// 2. Find the TS type for the ES node
const type = services.getTypeAtLocation(node.right);
// 3. Check the TS type's backing symbol for being an enum
if (type.symbol.flags & ts.SymbolFlags.Enum) {
context.report({
messageId: 'loopOverEnum',
node: node.right,
});
}
},
};
},
meta: {
docs: {
description: 'Avoid looping over enums.',
},
messages: {
loopOverEnum: 'Do not loop over enums.',
},
type: 'suggestion',
schema: [],
},
name: 'no-loop-over-enum',
defaultOptions: [],
});
```
:::note
Rules can retrieve their full backing TypeScript type checker with `services.program.getTypeChecker()`.
This can be necessary for TypeScript APIs not wrapped by the parser services.
:::
### Conditional Type Information
We recommend _against_ changing rule logic based solely on whether `services.program` exists.
In our experience, users are generally surprised when rules behave differently with or without type information.
Additionally, if they misconfigure their ESLint config, they may not realize why the rule started behaving differently.
Consider either gating type checking behind an explicit option for the rule or creating two versions of the rule instead.
:::tip
Documentation generators such as [`eslint-doc-generator`](https://github.com/bmish/eslint-doc-generator) can automatically indicate in a rule's docs whether it needs type information.
:::
## Testing
`@typescript-eslint/rule-tester` exports a `RuleTester` with a similar API to the built-in ESLint `RuleTester`.
It should be provided with the same `parser` and `parserOptions` you would use in your ESLint configuration.
Below is a quick-start guide. For more in-depth docs and examples [see the `@typescript-eslint/rule-tester` package documentation](../packages/Rule_Tester.mdx).
### Testing Untyped Rules
For rules that don't need type information, no constructor parameters are necessary:
```ts
import { RuleTester } from '@typescript-eslint/rule-tester';
import rule from './my-rule';
const ruleTester = new RuleTester();
ruleTester.run('my-rule', rule, {
valid: [
/* ... */
],
invalid: [
/* ... */
],
});
```
### Testing Typed Rules
For rules that do need type information, `parserOptions` must be passed in as well.
We recommend using `parserOptions.projectService` with options to allow a default project for each test file.
```ts
import { RuleTester } from '@typescript-eslint/rule-tester';
import rule from './my-typed-rule';
const ruleTester = new RuleTester({
languageOptions: {
parserOptions: {
projectService: {
allowDefaultProject: ['*.ts*'],
},
tsconfigRootDir: __dirname,
},
},
});
ruleTester.run('my-typed-rule', rule, {
valid: [
/* ... */
],
invalid: [
/* ... */
],
});
```
See [_Rule Tester_ > _Type-Aware Testing_](../packages/Rule_Tester.mdx#type-aware-testing) for more details.
---
# TypeScript ESLint Documentation
# Source: https://raw.githubusercontent.com/typescript-eslint/typescript-eslint/main/docs/developers/ESLint_Plugins.mdx
# Path: docs/developers/ESLint_Plugins.mdx
---
id: eslint-plugins
sidebar_label: Building ESLint Plugins
title: ESLint Plugins
---
:::important
This page describes how to write your own custom ESLint plugins using typescript-eslint.
You should be familiar with [ESLint's plugins guide](https://eslint.org/docs/latest/extend/plugins) and [typescript-eslint Custom Rules](./Custom_Rules.mdx) before writing custom plugins.
:::
Custom plugins that support TypeScript code and typed linting look very similar to any other ESLint plugin.
Follow the same general steps as [ESLint's plugins guide > _Creating a plugin_](https://eslint.org/docs/latest/extend/plugins#creating-a-plugin) to set up your plugin.
The required differences are noted on this page.
:::tip
See [**`eslint-plugin-example-typed-linting`**](https://github.com/typescript-eslint/examples/tree/main/packages/eslint-plugin-example-typed-linting) for an example plugin that supports typed linting.
:::
## Package Dependencies
Your plugin should have the following `package.json` entries.
For all `@typescript-eslint` and `typescript-eslint` packages, keep them at the same semver versions.
As an example, you might set each of them to `^8.1.2` or `^7.12.0 || ^8.0.0`.
### `dependencies`
[`@typescript-eslint/utils`](../packages/Utils.mdx) is required for the [`RuleCreator` factory to create rules](#rulecreator-usage).
### `devDependencies`
[`@typescript-eslint/rule-tester`](../packages/Rule_Tester.mdx) is strongly recommended to be able to [test rules with our `RuleTester`](./Custom_Rules.mdx).
### `peerDependencies`
Include the following to enforce the version range allowed without making users' package managers install them:
- `@typescript-eslint/parser` and any other parsers users are expected to be using
- `eslint`
- `typescript`
Those are all packages consumers are expected to be using already.
You don't need to declare any dependencies on `typescript-eslint` or `@typescript-eslint/eslint-plugin`.
Our setup guide ensures that the parser is automatically registered when configuring ESLint.
## `RuleCreator` Usage
We recommend including at least the following three properties in your plugin's [`RuleCreator` extra rule docs types](./Custom_Rules.mdx#extra-rule-docs-types):
- `description: string`: a succinct description of what the rule does
- `recommended?: boolean`: whether the rule exists in your plugin's shared _"`recommended`"_ config
- `requiresTypeChecking?: boolean`: whether the rule will use type information, for documentation generators such as [`eslint-doc-generator`](https://github.com/bmish/eslint-doc-generator)
For example, from [`eslint-plugin-example-typed-linting`'s `utils.ts`](https://github.com/typescript-eslint/examples/blob/main/packages/eslint-plugin-example-typed-linting/src/utils.ts):
```ts
import { ESLintUtils } from '@typescript-eslint/utils';
export interface ExamplePluginDocs {
description: string;
recommended?: boolean;
requiresTypeChecking?: boolean;
}
export const createRule = ESLintUtils.RuleCreator(
name =>
`https://github.com/your/eslint-plugin-example/tree/main/docs/${name}.md`,
);
```
## Type Checking and Configs
Most ESLint plugins export a _"`recommended`"_ [ESLint shared config](https://eslint.org/docs/latest/extend/shareable-configs).
Many ESLint users assume enabling a plugin's `recommended` config is enough to enable all its relevant rules.
However, at the same time, not all users want to or are able to enabled typed linting.
If your plugin's rules heavily use type information, it might be difficult to enable those in a `recommended` config.
You have roughly two options:
- Have your plugin's `recommended` config require enabling type information
- Have a separate config with a name like `recommendedTypeChecked`
Either way, explicitly mention the strategy taken in your docs.
:::info
Per [_Custom Rules_ > _Conditional Type Information_](./Custom_Rules.mdx#conditional-type-information), we recommend not changing rule logic based on whether type information is available.
:::
:::tip
See [**`eslint-plugin-example-typed-linting`**](https://github.com/typescript-eslint/examples/tree/main/packages/eslint-plugin-example-typed-linting) for an example plugin that supports typed linting.
:::
---
# TypeScript ESLint Documentation
# Source: https://raw.githubusercontent.com/typescript-eslint/typescript-eslint/main/docs/getting-started/Legacy_ESLint_Setup.mdx
# Path: docs/getting-started/Legacy_ESLint_Setup.mdx
---
id: legacy-eslint-setup
title: Legacy ESLint Setup
---
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
## Quickstart
These steps will get you running ESLint with our recommended rules on your TypeScript code as quickly as possible.
:::note
This page is for [ESLint's legacy config format](https://eslint.org/docs/latest/use/configure/configuration-files).
See [Getting Started](../getting-started/Quickstart.mdx) for [ESLint's new "flat" configuration format](https://eslint.org/docs/latest/use/configure/configuration-files-new).
:::
### Step 1: Installation
First, install the required packages for [ESLint](https://eslint.org), [TypeScript](https://typescriptlang.org), and this plugin:
```bash npm2yarn
npm install --save-dev @typescript-eslint/parser @typescript-eslint/eslint-plugin eslint typescript
```
### Step 2: Configuration
Next, create a `.eslintrc.cjs` config file in the root of your project, and populate it with the following:
```js title=".eslintrc.cjs"
/* eslint-env node */
module.exports = {
extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended'],
parser: '@typescript-eslint/parser',
plugins: ['@typescript-eslint'],
root: true,
};
```
:::info
If your project doesn't use ESM, naming the file as `.eslintrc.js` is fine. See [ESLint's Configuration Files docs](https://eslint.org/docs/user-guide/configuring/configuration-files) for more info.
:::
### Step 3: Running ESLint
Open a terminal to the root of your project and run the following command:
```bash
npx eslint .
```
```bash
yarn eslint .
```
```bash
pnpm eslint .
```
ESLint will lint all TypeScript compatible files within the current folder, and will output the results to your terminal.
## Details
- `parser: '@typescript-eslint/parser'` tells ESLint to use the [`@typescript-eslint/parser`](../packages/Parser.mdx) package you installed to parse your source files.
- This is required, or else ESLint will throw errors as it tries to parse TypeScript code as if it were regular JavaScript.
- `plugins: ['@typescript-eslint']` tells ESLint to load the [`@typescript-eslint/eslint-plugin`](../packages/ESLint_Plugin.mdx) package as a plugin.
- This allows you to use typescript-eslint's rules within your codebase.
- `extends: [ ... ]` tells ESLint that your config extends the given configurations.
- `eslint:recommended` is ESLint's inbuilt "recommended" config - it turns on a small, sensible set of rules which lint for well-known best-practices.
- `plugin:@typescript-eslint/recommended` is our "recommended" config - it's similar to `eslint:recommended`, except it turns on TypeScript-specific rules from our plugin.
- `root: true` is a generally good ESLint practice to indicate this file is the root-level one used by the project and ESLint should not search beyond this directory for config files.
## Next Steps
If you're having problems getting this working, please have a look at our [Troubleshooting & FAQs](../troubleshooting/faqs/General.mdx).
### Additional Configs
We recommend you consider enabling the following two configs:
- [`strict`](../users/Shared_Configurations.mdx#strict): a superset of `recommended` that includes more opinionated rules which may also catch bugs.
- [`stylistic`](../users/Shared_Configurations.mdx#stylistic): additional rules that enforce consistent styling without significantly catching bugs or changing logic.
```js title=".eslintrc.cjs"
/* eslint-env node */
module.exports = {
extends: [
'eslint:recommended',
// Remove this line
'plugin:@typescript-eslint/recommended',
// Added lines start
'plugin:@typescript-eslint/strict',
'plugin:@typescript-eslint/stylistic',
// Added lines end
],
parser: '@typescript-eslint/parser',
plugins: ['@typescript-eslint'],
root: true,
};
```
You can read more about these in our [shared configurations docs](../users/Shared_Configurations.mdx).
### Typed Linting
We also provide a plethora of powerful rules that utilize the power of TypeScript's type information.
[Visit the next page for a typed rules setup guide](./Typed_Linting.mdx).
### Documentation Resources
- You can read more about configuring ESLint [in their documentation on configuration](https://eslint.org/docs/user-guide/configuring).
- You can read more about the rules provided by ESLint [in their documentation on their rules](https://eslint.org/docs/rules/).
- You can read more about the rules provided by typescript-eslint in [our rules documentation](/rules).
---
# TypeScript ESLint Documentation
# Source: https://raw.githubusercontent.com/typescript-eslint/typescript-eslint/main/docs/getting-started/Quickstart.mdx
# Path: docs/getting-started/Quickstart.mdx
---
id: quickstart
title: Getting Started
slug: /getting-started/
pagination_next: getting-started/typed-linting
---
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
## Quickstart
This page is a quick-start for [ESLint's new "flat" config format](https://eslint.org/docs/latest/use/configure/configuration-files-new) to go from zero to linting with our recommended rules on your TypeScript code as quickly as possible.
:::note
- For the same guide but for [ESLint's legacy format](https://eslint.org/docs/latest/use/configure/configuration-files-deprecated) — see [Legacy ESLint Setup](./Legacy_ESLint_Setup.mdx).
- For quickstart information on linting with type information — see [Typed Linting](./Typed_Linting.mdx).
:::
### Step 1: Installation
First, install the required packages for [ESLint](https://eslint.org), [TypeScript](https://typescriptlang.org), and [our tooling](../packages/TypeScript_ESLint.mdx):
```bash npm2yarn
npm install --save-dev eslint @eslint/js typescript typescript-eslint
```
### Step 2: Configuration
Next, create an `eslint.config.mjs` config file in the root of your project, and populate it with the following:
```js title="eslint.config.mjs"
// @ts-check
import eslint from '@eslint/js';
import { defineConfig } from 'eslint/config';
import tseslint from 'typescript-eslint';
export default defineConfig(
eslint.configs.recommended,
tseslint.configs.recommended,
);
```
This code will enable our [recommended configuration](../users/Shared_Configurations.mdx) for linting.
#### Details
- `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 file extensions
The `.mjs` extension makes the file use the [ES modules (ESM)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules) format. Node interprets `.js` files in the [CommonJS (CJS)](https://nodejs.org/api/modules.html) format by default, but if you have `"type": "module"` in your `package.json`, you can also use `eslint.config.js`.
### Step 3: Running ESLint
Open a terminal to the root of your project and run the following command:
```bash
npx eslint .
```
```bash
yarn eslint .
```
```bash
pnpm eslint .
```
ESLint will lint all TypeScript compatible files within the current folder, and will output the results to your terminal.
## Next Steps
If you're having problems getting this working, please have a look at our [Troubleshooting & FAQs](../troubleshooting/faqs/General.mdx).
### Additional Configs
We recommend you consider enabling the following two configs:
- [`strict`](../users/Shared_Configurations.mdx#strict): a superset of `recommended` that includes more opinionated rules which may also catch bugs.
- [`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 defineConfig(
eslint.configs.recommended,
// Remove this line
tseslint.configs.recommended,
// Add this line
tseslint.configs.strict,
// Add this line
tseslint.configs.stylistic,
);
```
You can read more about these in our [shared configurations docs](../users/Shared_Configurations.mdx).
### Typed Linting
We also provide a plethora of powerful rules that utilize the power of TypeScript's type information.
[Visit the next page for a typed rules setup guide](./Typed_Linting.mdx).
## Documentation Resources
- You can read more about configuring ESLint [in their documentation on configuration](https://eslint.org/docs/user-guide/configuring).
- You can read more about the rules provided by ESLint [in their documentation on their rules](https://eslint.org/docs/rules/).
- You can read more about the rules provided by typescript-eslint in our [rules documentation](/rules).
---
# TypeScript ESLint Documentation
# Source: https://raw.githubusercontent.com/typescript-eslint/typescript-eslint/main/docs/getting-started/Typed_Linting.mdx
# Path: docs/getting-started/Typed_Linting.mdx
---
id: typed-linting
title: Linting with Type Information
---
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
Some typescript-eslint rules utilize TypeScript's type checking APIs to provide much deeper insights into your code.
This requires TypeScript to analyze your entire project instead of just the file being linted.
As a result, these rules are slower than traditional lint rules but are much more powerful.
To enable typed linting, there are two small changes you need to make to your config file:
1. Add `TypeChecked` to the name of any preset configs you're using, namely `recommended`, `strict`, and `stylistic`.
2. Add `languageOptions.parserOptions` to tell our parser how to find the TSConfig for each source file.
```js title="eslint.config.mjs"
import eslint from '@eslint/js';
import { defineConfig } from 'eslint/config';
import tseslint from 'typescript-eslint';
export default defineConfig(
eslint.configs.recommended,
// Remove this line
tseslint.configs.recommended,
// Added lines start
tseslint.configs.recommendedTypeChecked,
{
languageOptions: {
parserOptions: {
projectService: true,
},
},
},
// Added lines end
);
```
In more detail:
- `tseslint.configs.recommendedTypeChecked` is a [shared configuration](../users/Shared_Configurations.mdx). It contains recommended rules that additionally require type information.
- `parserOptions.projectService: true` indicates to ask TypeScript's type checking service for each source file's type information (see [Parser > Project Service](../packages/Parser.mdx#projectservice)).
- `parserOptions.tsconfigRootDir` tells our parser the absolute path of your project's root directory (see [Parser > tsconfigRootDir](../packages/Parser.mdx#tsconfigrootdir)).
1. Add `-type-checked` to the name of any preset configs you're using, namely `recommended`, `strict`, and `stylistic`.
2. Add `parserOptions` to tell our parser how to find the TSConfig for each source file.
```js title=".eslintrc.cjs"
/* eslint-env node */
module.exports = {
extends: [
'eslint:recommended',
// Remove this line
'plugin:@typescript-eslint/recommended',
// Add this line
'plugin:@typescript-eslint/recommended-type-checked',
],
plugins: ['@typescript-eslint'],
parser: '@typescript-eslint/parser',
// Added lines start
parserOptions: {
projectService: true,
tsconfigRootDir: __dirname,
},
// Added lines end
root: true,
};
```
In more detail:
- `plugin:@typescript-eslint/recommended-type-checked` is a [shared configuration](../users/Shared_Configurations.mdx). It contains recommended rules that additionally require type information.
- `parserOptions.projectService: true` indicates to ask TypeScript's type checking service for each source file's type information (see [Parser > `projectService`](../packages/Parser.mdx#projectservice)).
- `parserOptions.tsconfigRootDir` tells our parser the absolute path of your project's root directory (see [Parser > `tsconfigRootDir`](../packages/Parser.mdx#tsconfigrootdir)).
:::caution
Your ESLint config file may start receiving a parsing error about type information.
See [our TSConfig inclusion FAQ](../../troubleshooting/typed-linting#i-get-errors-telling-me-eslint-was-configured-to-run--however-that-tsconfig-does-not--none-of-those-tsconfigs-include-this-file).
:::
With that done, run the same lint command you ran before.
You may see new rules reporting errors based on type information!
## Shared Configurations
If you enabled the [`strict` shared config](../users/Shared_Configurations.mdx#strict) and/or [`stylistic` shared config](../users/Shared_Configurations.mdx#stylistic) in a previous step, be sure to replace them with [`strictTypeChecked`](../users/Shared_Configurations.mdx#strict-type-checked) and [`stylisticTypeChecked`](../users/Shared_Configurations.mdx#stylistic-type-checked) respectively to add their type-checked rules.
```js title="eslint.config.mjs"
export default defineConfig(
eslint.configs.recommended,
// Removed lines start
tseslint.configs.strict,
tseslint.configs.stylistic,
// Removed lines end
// Added lines start
tseslint.configs.strictTypeChecked,
tseslint.configs.stylisticTypeChecked,
// Added lines end
// ...
);
```
```js title=".eslintrc.cjs"
/* eslint-env node */
module.exports = {
extends: [
'eslint:recommended',
// Removed lines start
'plugin:@typescript-eslint/strict',
'plugin:@typescript-eslint/stylistic',
// Removed lines end
// Added lines start
'plugin:@typescript-eslint/strict-type-checked',
'plugin:@typescript-eslint/stylistic-type-checked',
// Added lines end
],
// ...
};
```
You can read more about the rules provided by typescript-eslint in our [rules docs](/rules) and [shared configurations docs](../users/Shared_Configurations.mdx).
## Performance
Typed rules come with a catch.
By using typed linting in your config, you incur the performance penalty of asking TypeScript to do a build of your project before ESLint can do its linting.
For small projects this takes a negligible amount of time (a few seconds or less); for large projects, it can take longer.
Most of our users do not mind this cost as the power and safety of type-aware static analysis rules is worth the tradeoff.
Additionally, most users primarily consume lint errors via IDE plugins which, through caching, do not suffer the same penalties.
This means that generally they usually only run a complete lint before a push, or via their CI, where the extra time often doesn't matter.
**We strongly recommend you do use type-aware linting**, but the above information is included so that you can make your own, informed decision.
See [Troubleshooting > Typed Linting > Performance](../troubleshooting/typed-linting/Performance.mdx) for more information.
## Troubleshooting
If you're having problems with typed linting, please see our [Troubleshooting FAQs](../troubleshooting/faqs/General.mdx) and in particular [Troubleshooting > Typed Linting](../troubleshooting/typed-linting/index.mdx).
For details on the parser options that enable typed linting, see:
- [Parser > `projectService`](../packages/Parser.mdx#projectservice): our recommended option, with settings to customize TypeScript project information
- [Parser > `project`](../packages/Parser.mdx#project): an older option that can be used as an alternative
---
# TypeScript ESLint Documentation
# Source: https://raw.githubusercontent.com/typescript-eslint/typescript-eslint/main/docs/maintenance/Branding.mdx
# Path: docs/maintenance/Branding.mdx
---
id: branding
title: Branding
---
This document serves as a guide for how we generally describe or represent typescript-eslint.
It's fine if you don't always adhere to it.
## Terminology
### Name
Our project name is **_"typescript-eslint"_**.
We sometimes refer to it as _"ts-eslint"_ for short.
_"typescript-eslint"_ is preferred over _"TypeScript ESLint"_ or _"TypeScript-ESLint"_ because ESLint and TypeScript are written in abbreviated Pascal Case.
Combining lowercase with a dash helps differentiate us.
### Slogan
> Powerful static analysis for JavaScript and TypeScript.
## Visuals
Our primary brand color is `#2656c7`, the halfway point between ESLint's `#4b32c3` purple and TypeScript's `#007acc` blue.
You can call it _blurple_ if you want.
Our logo is also a halfway between [ESLint's logo](https://en.wikipedia.org/wiki/ESLint#/media/File:ESLint_logo.svg) and [TypeScript's logo](https://en.wikipedia.org/wiki/TypeScript#/media/File:Typescript.svg):
- [Logo PNG download](/img/logo.png)
- [Logo SVG download](/img/logo.svg)
---
# TypeScript ESLint Documentation
# Source: https://raw.githubusercontent.com/typescript-eslint/typescript-eslint/main/docs/maintenance/Contributor_Tiers.mdx
# Path: docs/maintenance/Contributor_Tiers.mdx
---
id: contributor-tiers
title: Contributor Tiers
---
These tiers of contributors, committers, and maintainers roughly reflect how we've worked the past several years.
| Tier |
Entry Requirements |
Monthly Expectations |
Monthly Reimbursement |
| Contributor |
1 point |
(none)
|
(none)
|
| Code Contributor |
1 point in authoring pull requests |
(none)
|
(none)
|
| Committer |
~5 points in issues
~5 points in authoring pull requests
~15 points total
2 of 4 consecutive active months
|
~10 points in total (across all activities mentioned in the [Pointing](#pointing) section)
Committers may stick to a focus area of contributions, or may expand to contribute throughout the repo.
|
~1 share / active month |
| Maintainer |
~10 points in issues
~10 points in authoring pull requests
~30 points total
3 of 6 active months
|
~20 points in total
|
~2 shares / active month |
:::note
We treat everything here as approximate numbers.
We're a small enough team to informally discuss changes ad hoc and allow off-by-one-or-two months.
:::
## Advancement
Are you looking to graduate from _contributor_ to _committer_?
Great!
Roughly speaking, we're looking for folks who are interested in growing towards:
- Being able to contribute to docs & ideation discussions, not just chores + rule fixes & features
- Being able to empathetically understand the needs of lint rule users (i.e. not just their own personal preferences)
- Consistently sending high-quality issues and PRs
- It's expected that some will have long rounds of discussion; we're more looking to avoid making "common" mistakes repeatedly (requesting review with failing builds, clear large gaps in logic, etc.)
If you've been sending issues and pull requests to typescript-eslint for a few months and want to get more involved, please reach out to one of the maintainers over Discord or email.
We'd love to support you in joining the team.
## Pointing
Although it's impossible to accurately estimate software projects, we want to roughly establish expectations of effort+time spent on the tiers.
These are all rough estimations and should be taken as approximate starting guides to consider.
We treat both the creation and review of issues and PRs along the rough scale of:
| Size |
Description |
Points |
Examples |
| Trivial |
Small typos or single-file bugfixes |
1 |
#6976
,{' '}
#6992
|
| Straightforward |
2-3 files at most, with minimal logical changes |
2 |
#6780
,{' '}
#6910
|
| Large |
Multi-file logical changes that require real review+thought |
3 |
#6107
,{' '}
#6907
|
| Unusual |
Dozen+ file logical changes that require deep investigation |
≥5* |
#6084
,{' '}
#6777
|
> \*Unusually large efforts may be >5 points at maintainer discretion depending on time spent.
Any other activities (e.g. responding to Discord threads, working on upstream dependencies, …) should be treated as gaining points equal to their nearest equivalent point task in terms of complexity and effort.
### Recognition
We place committers and maintainers on [typescript-eslint.io/maintenance-team](./Team.mdx).
See existing bios for examples of what information will be asked.
:::note
You can decline to opt into the site recognition, and you can always opt out after the fact.
Nothing is mandatory.
We just like including recognition as thanks for working with us. 💕
:::
## Reimbursement
Team members will be reimbursed the minimum of their activity level and their tier.
Each month:
- Committers and maintainers who hit their expectation receive their full shares
- Committers and maintainers who hit roughly half their expectation receive half shares
Reimbursements are generally handled through [our Open Collective page](https://opencollective.com/typescript-eslint).
### Community Reimbursements
Contributors who contribute nontrivial changes in a month (roughly ≥5 points and at least one _Large_ item) may be privately nominated at any time by a committer or maintainer to be reimbursed at the equivalent shares.
Our intention is to always do this for contributors who submit _Large_ or greater contributions and don't need significant assistance in getting them merged.
---
# TypeScript ESLint Documentation
# Source: https://raw.githubusercontent.com/typescript-eslint/typescript-eslint/main/docs/maintenance/Governance.mdx
# Path: docs/maintenance/Governance.mdx
---
id: governance
title: Governance
---
---
# TypeScript ESLint Documentation
# Source: https://raw.githubusercontent.com/typescript-eslint/typescript-eslint/main/docs/maintenance/Issues.mdx
# Path: docs/maintenance/Issues.mdx
---
id: issues
title: Issues
---
This document serves as a guide for how you might manage our [GitHub Issues](https://docs.github.com/issues), also known as issue triaging.
Use your best judgement when triaging issues, and most of all remember to be **encouraging, friendly, and kind** when responding to users.
Many users are new to open source and/or typed linting.
It's imperative we give them a positive, uplifting experience.
:::tip
If you're ever unsure on any part of issue management, don't hesitate to loop in a maintainer that has more context to help!
:::
## Governance
Per the scales from [Contribution Tiers > Pointing](./Contributor_Tiers.mdx#pointing):
- Straightforward: at reviewer discretion, may be marked as approved by any committer or maintainer.
This includes docs enhancements, bug fixes, and feature additions.
- Non-straightforward: may be marked as approved with either two committer approvals or one maintainer approval.
These include significant internal refactors and non-breaking public API changes.
- "Unusual"-categorized: require a public discussion followed by two maintainer approvals.
These include significant refactors with cross-project and public API ramifications.
## Issue Flow
:::note
We include a set of common responses to issues in [`.github/replies.yml`](https://github.com/typescript-eslint/typescript-eslint/blob/main/.github/replies.yml), intended to be used with the [Refined Saved Replies](https://github.com/JoshuaKGoldberg/refined-saved-replies) extension.
Don't treat these as exact responses you must use: they're just a starting copy+paste helper.
Please do adopt your specific responses to your personal tone and to match the thread for non-straightforward issues.
:::
[Issues pending triage](https://github.com/typescript-eslint/typescript-eslint/issues?q=is%3Aopen+is%3Aissue+label%3Atriage) are searchable with the `triage` label.
That label is added automatically when a new issue is created.
Most issues go through the following review flow when created or updated:
1. A maintainer ensures the issue is valid:
- If the poster didn't fill out an appropriate template with enough information:
- Add the `please fill out the template` and `awaiting response` labels, and remove the `triage` label
- Ask the poster for more information using a _Needs More Info_ response
- If it's a duplicate of an issue that already exists:
- Add the `duplicate` label and remove the `triage` label
- If it's an obvious duplicate, post a _Clearly Duplicate Issue_ response linking to the existing issue
- If it's not an obvious duplicate, link to the existing issue and explain why
- Close the issue as _not planned_
- If the code is working as intended:
- Add the `working as intended` label and remove the `bug` and `triage` labels
- If the behavior is due to the user doing something wrong, such as an incorrect config:
- Add the `fix: user error` label
- [This issue search has some examples of closing comments](https://github.com/typescript-eslint/typescript-eslint/issues?q=is%3Aissue+sort%3Aupdated-desc+label%3A%22fix%3A+user+error%22+is%3Aclosed)
- If the behavior is otherwise expected, [this issue search has some examples of closing comments](https://github.com/typescript-eslint/typescript-eslint/issues?q=is%3Aissue+sort%3Aupdated-desc+label%3A%22working+as+intended%22+-label%3A%22fix%3A+user+error%22+is%3Aclosed+)
- You needn't go into too much detail in your comment - just enough to explain it
- Close the issue as _not planned_
- If issue contains an enhancement-like request that is unlikely to be implemented on the typescript-eslint side:
- Add the `wontfix` label and remove `triage` label
- [Issue search with some examples of closing comments](https://github.com/typescript-eslint/typescript-eslint/issues?q=is%3Aissue+sort%3Aupdated-desc+label%3Awontfix+is%3Aclosed)
- If there're any alternatives or approaches to meet the request, it would be nice to suggest them
- Close the issue as _not planned_
- If the issue requires further discussion or community engagement evaluation:
- Add the `evaluating community engagement` label and remove the `triage` label
2. If the report is valid:
- Remove the `triage` label
- Add the `team assigned` label if you think only a member of the team should tackle it, or `accepting prs` if anybody could
3. If you know the rough steps for a fix, consider writing a comment with links to codebase to help someone put together a fix
4. If you think that the fix is relatively straightforward, consider also adding the `good first issue` label
Whenever an issue is waiting for the reporter to provide more information, it should be given the `awaiting response` label.
When more information is provided:
- If you have time to go through the triage flow again, do so
- If you don't have time, add the `triage` label and remove the `awaiting response` label
:::tip
If your link is both a "permalink" (includes a commit hash instead of a branch name) and has a line number/line range then GitHub will embed the code in your comment.
When viewing a file in GitHub pressing `y` will update the URL to a "permalink" with the current commit hash, then you can select the relevant lines and paste that URL into the comment.
:::
### Looking for Duplicates
It's worth noting that, occasionally, a user will intentionally raise a duplicate issue because they feel the original issue was closed when it shouldn't have been.
If this is the case, you should read the original issue to gather context, understand the reason for it being closed, and determine if the new issue raises any new or relevant point that requires addressing.
### Determining Whether Code is Working As Intended
As you become more familiar with the codebase and how everything works, this will be easier to do intuitively, but to begin with, this will likely involve investigating the documentation, code, and tests to determine if it's a bug or working as intended.
In general, if there is a passing test or documented example that is the same as or similar to the repro code — that indicates it's working as intended.
If you can't find anything that matches, use your best judgement based on the spirit of the code.
### Community Engagement Evaluation
In most cases, maintainers have a pretty good idea of how people write code and what most users of the typescript-eslint tooling want.
However, there are cases when maintainers can't confidently choose the most reasonable approach to solving a particular problem:
- The issue subject relates to a library/framework that the maintainers are not familiar with. Therefore, they don't know the idiomatic patterns associated with it.
- There is a new syntax or a new feature - sometimes it's hard to guess how people might use that feature.
- The issue was about to be closed, but someone made a compelling argument. This requires further discussion to find a viewpoint that most people agree on.
3-6 months after the issue is labeled `evaluating community engagement`, the engagement of community is evaluated:
- If the community was active and common ground was found, the issue is labeled as `accepting prs` or `team assigned`
- Otherwise, the issue is closed as _not planned_ with the `wontfix` label
For requests that can be implemented outside of typescript-eslint, be sure to mention any relevant APIs such as [Custom Rules](../developers/Custom_Rules.mdx) that can be used.
## Skipping Steps
As you become more familiar with the codebase and how it's supposed to behave you'll be able to skip steps or do things out of order as you see fit.
For example, you may be able to identify if a bug report is "working as intended", or you might recognize an issue as a duplicate without having a completely filled-out issue.
In such cases you can forgo the back-and-forth and just skip to the closing steps.
## Specific Issue Types
### 🐛 Bug Reports
#### 🐞 "Simple" Bugs
A simple bug is a bug that can be reproduced in a single TS file plus an ESLint config (and possibly a TSConfig) - i.e. an issue reproducible on [our playground](/play).
The vast majority of bug reports fall into this category.
If you cannot reproduce the issue as described using the issue's provided playground reproduction, it has not provided enough information.
Consider using a specific response like the _Needs Playground Reproduction_ response.
#### 🦟 "Complex" Bugs
A complex bug is a bug that requires multiple files to reproduce.
This is the rarer case, but does happen when people are using library types or if there are issues when types are imported.
These bugs should be reported with a link to a GitHub repository that can be checked out to reproduce the issue.
If you cannot reproduce the issue as described using repository's README.md and issue description, it has not provided enough information.
Consider using a specific response like the _Needs Full Reproduction_ response.
### 🏗 Feature Requests
For any feature request, make sure the requested support is either:
- Very useful for at least one commonly used way to run TypeScript (e.g. tsc-built CLI package; bundler-managed web app)
- Relevant for _most_ projects that would be using typescript-eslint
We avoid features that:
- Are only relevant for a minority of users, as they aren't likely worth the maintenance burden
- Aren't TypeScript-specific (e.g. should be in ESLint core instead)
- Are only relevant with specific userland frameworks or libraries, such as Jest or React
- Are for "formatting" functionality (we [strongly recommend users use a separate dedicated formatter](../users/What_About_Formatting.mdx))
#### ✨ Rule Enhancements
We're generally accepting of rule enhancements that meet the above feature request criteria.
If a rule enhancement would substantially change the target area of the rule, consider whether it should instead be a new rule.
Common signs of this are the rule's original name now being inaccurate, or some options being relevant just for the old functionality.
Enhancements that can cause new reports to be reported are considered breaking changes.
We have two common strategies for them:
- Treat the enhancement as a breaking change, and block merging it until the next major version
- Add an option to disable the new logic: which is a breaking change if opt-in, and a non-breaking change if opt-out
- Add an option to enable the new logic: which is a breaking change if opt-out, and a non-breaking change if opt-in
See [Can we standardize logical direction of rule options?](https://github.com/typescript-eslint/typescript-eslint/discussions/6101) for context on naming options.
For enhancements meant to limit which kinds of nodes the rule targets, mark the issue as blocked on [RFC: Common format to specify a type or value as a rule option](https://github.com/typescript-eslint/typescript-eslint/discussions/6017).
#### 🚀 New Rules
We're generally accepting of new rules that meet the above feature request criteria.
The biggest exception is rules that can roughly be implemented with [`@typescript-eslint/no-restricted-types`](/rules/no-restricted-types) and/or [`no-restricted-syntax`](https://eslint.org/docs/latest/rules/no-restricted-syntax).
## Pruning Old Issues
Every so often, we like to [search for open issues `awaiting response`](https://github.com/typescript-eslint/typescript-eslint/issues?q=is%3Aopen+is%3Aissue+label%3A%22awaiting+response%22) to find ones that might have been forgotten.
Our flow for issues that have been waiting for >=1 month is:
1. Ping the author with a message like the _Checking In_ template
1. Add the `stale` label to the issue
1. Wait 2 weeks
1. If they still haven't responded, close the issue with a message like the _Pruning Stale Issue_ template
---
# TypeScript ESLint Documentation
# Source: https://raw.githubusercontent.com/typescript-eslint/typescript-eslint/main/docs/maintenance/Pull_Requests.mdx
# Path: docs/maintenance/Pull_Requests.mdx
---
id: pull-requests
title: Pull Requests
---
This document serves as a guide for how you might review pull requests.
Use your best judgement when reviewing PRs, and most of all remember to be **kind, friendly, and encouraging** when responding to users.
Many users are new to open source and/or typed linting.
It's imperative we give them a positive, uplifting experience.
:::tip
If you're a new team member, we encourage you to review PRs as soon as you feel comfortable doing so!
In addition to benefitting the project, it's a great way to learn more about the codebase and project in general.
Consider starting with areas you're most familiar with, and work your way up to more unfamiliar and complex PRs as you gain experience.
If you're ever unsure on any part of PR reviews, don't hesitate to loop in a team member who has more context to help!
:::
## Governance
Per the scales from [Contribution Tiers > Pointing](./Contributor_Tiers.mdx#pointing):
- Straightforward: At reviewer discretion, may be merged with a single approval by any committer or maintainer.
This includes docs enhancements, bug fixes, and feature additions.
- Non-straightforward: may be merged with either two committer approvals or one maintainer approval.
These include multi-package internal refactors and non-breaking public API changes.
- "Unusual"-categorized: require two maintainer approvals.
These include significant refactors with cross-project and public API ramifications.
## PR Review Flow
:::note
We include a set of common responses to PRs in [`.github/replies.yml`](https://github.com/typescript-eslint/typescript-eslint/blob/main/.github/replies.yml), intended to be used with the [Refined Saved Replies](https://github.com/JoshuaKGoldberg/refined-saved-replies) extension.
Don't treat these as exact responses you must use: they're just a starting copy+paste helper.
Please do adopt your specific responses to your personal tone and to match the thread for non-straightforward PRs.
:::
Open pull requests ideally switch between two states:
- Ready for review: either newly created or after [review is re-requested](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/reviewing-changes-in-pull-requests/about-pull-request-reviews#re-requesting-a-review)
- Waiting for author activity: either by virtue of [being a draft](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/about-pull-requests#draft-pull-requests) or having the [`awaiting response` label](https://github.com/typescript-eslint/typescript-eslint/pulls?q=is%3Apr+is%3Aopen+label%3A%22awaiting+response%22)
Add the `awaiting response` label to a PR and remove `1 approval` if it exists whenever you post a request for changes.
It will be automatically removed if the author re-requests review.
### Be Kind
Above all else, be _encouraging_ and _friendly_ in tone.
- Phrase feedback as opportunities for improvement rather than chastising.
- Call out any positive aspects you see - especially in larger pull requests.
- Use happy emojis frequently.
- If you have the energy, post a fun (but not inappropriate) GIF with your review.
- We often use the _GIFs for Github_ extension: available as [GIFs for GitHub (Chrome)](https://chrome.google.com/webstore/detail/gifs-for-github/dkgjnpbipbdaoaadbdhpiokaemhlphep) and [GIFs for GitHub (Firefox)](https://addons.mozilla.org/en-US/firefox/addon/gifs-for-github).
Pull requests are the first time many community members meaningfully interact with us - or, oftentimes, any open source maintainers at all.
It's important that we provide a positive, uplifting experience. ❤️
### Reviewing a PR
Before reviewing a pull request, try to look back over the backing issue to (re-)familiarize yourself with it.
You may find it useful to:
- Attempt to simplify the provided reduction (["code golf"](https://en.wikipedia.org/wiki/Code_golf))
- Look back through previous issues and PRs around the same area of code / lint rule
If there's no backing issue:
- If the PR is a straightforward docs or tooling fix that doesn't impact users, it's ok to review it as-is
- Otherwise, add the `please fill out the template` label and post a comment like the _Needs Issue_ template
#### Common Things to Look For
- Style: that can you read through the code easily, there are comments for necessary tricky areas, and not unnecessary comments otherwise.
- Try not to nitpick things that don't matter.
- If something is standard in the repo but not enforced, consider mentioning it as a non-blocking comment and filing an issue to enforce it.
- Thoroughness: does it handle relevant edge cases? Commonly:
- Generics and type parameters (see: `getConstrainedTypeAtLocation`).
- Parenthesis and whitespace (see: `getWrappingFixer`).
- Unions and intersections (see: `unionConstituents` and `intersectionConstituents`).
- Unit tests:
- Both "positive" and "negative" ("valid" and "invalid") cases exist, if reasonably possible to test for.
- Fixes and suggestions, if present, don't remove `//` or `/*` comments
- `invalid` lint rule errors include line and column information
- Valid syntax edge cases don't cause the rule to crash, even if they cause a type error in TypeScript
#### Individual Comments
Post about one comment per area of praise note, suggested change, or non-actionable note.
It's fine to use multiple ancillary comments to indicate _"(also here)"_ notes, but don't overwhelm with requests.
:::tip
If you're posting more than a couple types of comments, consider prefixing them with category indicators such as `[Docs]`, `[Praise]`, `[Testing]`, etc.
This helps avoid the review feeling like a huge slog of big requests.
:::
Be clear in each of your comments what you're looking for or saying.
Err on the side of providing more information than you think is needed.
Try to default to a questioning tone for points that aren't clear bugs.
Encourage authors to think on your suggestions: _"I think (xyz), but am not sure - what do you think?"_.
#### Preliminary or Repeat Reviews
Sometimes you may want to post a preliminary review, and/or realize later on you missed something in an earlier review.
Both are reasonable and fine.
For preliminary reviews, be clear with what scale you're reviewing at: _"Reviewing on architecture now, will look in more detail once it's settled"_.
For repeat reviews, be clear when it's something you missed earlier and/or there's new information.
Don't apologize if the missed information was only made clear because of requested changes - this is part of the review process!
### Approvals
If the PR addresses a time critical task, such as a security fix or `main` branch build break, go ahead and squash merge it.
Otherwise, upon completing your review, if the build is passing and you have no blockers, approve it on GitHub.
Then:
- If there isn't a `1 approval` label or existing approval, add the `1 approval` label
- If there's already `1 approval` and/or it's been a week since the last request for changes, go ahead and squash merge
- For straightforward PRs that don't impact users, you can wait 3 days instead
There's no need to reset waiting periods for minor fixups from code reviews of otherwise approved code.
We try to leave PRs open for at least a week to give reviewers who aren't active every day a chance to get to it.
### Other States
#### External Blockers
If the PR is blocked on something, such as an external API or discussion in an issue, add the appropriate `blocked by *` label.
Explain why in a comment that links to at least a tracking issue for the blocker.
#### Out-of-Band Questions
Authors sometimes separately ask questions as comments on PRs, sometimes including an `@` tag.
Put back the `awaiting response` label if you answer the questions.
Don't worry if you miss some of these questions; we prefer going through the formal re-requesting review to make sure the `awaiting response` label is removed as needed.
## Pruning Old PRs
Every so often, we like to [search for open PRs `awaiting response`](https://github.com/typescript-eslint/typescript-eslint/pulls?q=is%3Aopen+is%3Apr+label%3A%22awaiting+response%22) to find ones that might have been forgotten.
Our flow for PRs that have been waiting for >=1 month is:
1. Ping the author with a message like the _Checking In_ template
2. Add the `stale` label to the PR
3. Wait 2 weeks
4. If they still haven't responded, close the PR with a message like the _Pruning Stale PR_ template
## Searching for PRs
Assorted other queries for PRs include:
- [All PRs you commented on](https://github.com/typescript-eslint/typescript-eslint/pulls?q=is%3Aopen+is%3Apr+commenter%3A%40me)
- [All non-draft, non-`awaiting response` PRs](https://github.com/typescript-eslint/typescript-eslint/pulls?q=is%3Aopen+is%3Apr+-label%3A%22awaiting+response%22+-is%3Adraft)
- [All non-draft, non-`awaiting response` PRs not blocked or already approved](https://github.com/typescript-eslint/typescript-eslint/pulls?q=is%3Aopen+is%3Apr+-label%3A%22awaiting+response%22+-is%3Adraft+-label%3A%22blocked+by+another+PR%22+-label%3A%22blocked+by+another+issue%22+-label%3A%22blocked+by+external+API%22+-review%3Aapproved+)
If you have time, consider occasionally looking through old PRs to make sure there aren't any questions left unanswered for weeks.
---
# TypeScript ESLint Documentation
# Source: https://raw.githubusercontent.com/typescript-eslint/typescript-eslint/main/docs/maintenance/Releases.mdx
# Path: docs/maintenance/Releases.mdx
---
id: releases
title: Releases
---
[Users > Releases](../users/Releases.mdx) describes how our automatic releases are done.
There is generally no maintenance activity we need to take for the weekly releases.
However, there are two kinds of releases we infrequently go through that each require manual effort.
## Major Releases
Per [Users > Releases > Major Releases](../users/Releases.mdx#major-releases), we infrequently release major versions with accumulated breaking changes.
### 1. Pre-Release Preparation
1. Create a milestone by the name of the release [example: [Milestone 6.0.0](https://github.com/typescript-eslint/typescript-eslint/milestone/8)].
1. If an issue for changes to recommended rule configs doesn't yet exist, create one [example: [Changes to the `recommended` sets for 5.0.0](https://github.com/typescript-eslint/typescript-eslint/issues/5900)].
1. Add any breaking changes intended for the release to that milestone.
1. Search for source code comments (excluding `CHANGELOG.md` files) that mention deprecated code and/or a todo for the new major version, and create corresponding issues in that milestone.
- For example, for a new major version 8, searches might include:
- `/deprecated|todo/i`
- `/v8/i`
- `/todo.*v?8/i`
1. Create an issue to raise the minimum versions of dependencies [example: [Enhancement: Raise minimum versions of dependencies for v8](https://github.com/typescript-eslint/typescript-eslint/issues/8929)]
1. Create two new branches off `main` in the project repository (not a personal fork):
- `v${major}`
- `v${major}-canary-auto-release`
1. Raise a PR from `v${major}-canary-auto-release` to `main` modifying [`ci.yml` workflow](https://github.com/typescript-eslint/typescript-eslint/blob/main/.github/workflows/ci.yml) and README.md [example: [chore: add auto-canary release for v6](https://github.com/typescript-eslint/typescript-eslint/pull/5883)]:
- `ci.yml`:
- Under `push:` > `branches:` at the beginning of the file, add a `- v${major}` list item.
- Add a `publish_canary_version_v${major}` step the same as `publish_canary_version` except:
- Change the `if` condition's branch check to: `if: github.ref == 'refs/heads/v${major}'`.
- Its publish command should be `npx nx release publish --tag rc-v${major} --verbose`.
- `README.md`:
- Add a link to a `v${major}--typescript-eslint.netlify.app` preview deploy environment on Netlify that you create for the branch.
- `docusaurus.config.mts`: updating the `supportedMajorVersion` variable
- Merge this into `main` once reviewed and rebase the `v${major}` branch.
1. Configure the https://github.com/ldez/gha-mjolnir action to auto-close issues when PRs are merged to the `v${major}` branch (GitHub doesn't by default): see [`close-v8-issues.yml`](https://github.com/auvred/typescript-eslint/blob/b77e94dbd8ac7fd59c92527e13d241d6b26908b1/.github/workflows/close-v8-issues.yml) for reference
#### 1a. Shared Config Changes
Major versions are our only real chance to change the values in our stable `recommended*` and `stylistic*` configs.
In parallel to the general PR flow of the major version:
1. Create a `v${major}` channel on the typescript-eslint Discord
1. Create a discussion with a table summarizing any proposed rule changes [example: [Changes to configurations for 6.0.0](https://github.com/typescript-eslint/typescript-eslint/discussions/6014)]
1. Post that discussion on the typescript-eslint Discord and on social media
1. Once the greater of (1 month) and (discussion settling down) has passed, file an issue and send a corresponding PR to the `v${major}` branch making the corresponding changes [example: [Configs: Apply changes to config presets for v6](https://github.com/typescript-eslint/typescript-eslint/issues/6759)]
#### 1b. Voluntary Community Testing
In parallel to the shared config changes work, make sure to test out the beta version on popular community projects willing to try it out.
1. Create a pinned issue offering to try out the new version's beta for end users (example: [Try out v8 beta on various influential community repos](https://github.com/typescript-eslint/typescript-eslint/issues/9141))
- Ask each community repo if they'd be interested in trying out the new version, such as in their Discord or on their issue tracker.
- Each community project that's indicated willingness to receive a PR should have one.
1. Create a pinned issue offering to try the new version's beta for downstream plugins (example: [Try out v8 beta on various influential plugins](https://github.com/typescript-eslint/typescript-eslint/issues/9501))
- These PRs can be sent without asking, as a friendly courtesy.
1. Once the proposed _Shared Config Changes_ are merged into the `v${major}` branch, send a draft PR to each project with the new beta version.
#### 1c. Tracking Issue for Support
If there are behavioral breaking changes in the new major version, consider also creating a tracking issue showing support across popular plugins.
To do this:
1. Create a pinned issue (example: [📈 Tracking: typescript-eslint v8 support](https://github.com/typescript-eslint/typescript-eslint/issues/9720))
2. For each plugin you're familiar with, try sending a draft PR to them with a description of what you're doing (example: [chore: bump typescript-eslint to v8](https://github.com/vitest-dev/eslint-plugin-vitest/pull/479))
3. Make sure you're subscribed to notifications on that issue and any PRs, and update the table regularly
#### 1d. Post Community Testing Config Touchups
There may be additional changes to preset configs discovered as part of the community testing.
If that's the case:
1. Create a discussion describing the suggested changes [example: [Configs: Last round of "final" changes to configs for v6](https://github.com/typescript-eslint/typescript-eslint/discussions/7130)].
1. Post this new discussion in the previous config changes one, in the typescript-eslint Discord, and on social media.
1. Once the greater of (2 weeks) and (discussion settling down) has passed
If possible, we prefer to avoid making a second round of config changes.
These should only be done for feedback that consistently comes up in community testing.
### 2. Merging Breaking Changes
1. Send a PR from `v${major}` to `main` [example: [v6.0.0](https://github.com/typescript-eslint/typescript-eslint/pull/5886)].
1. Change all [breaking change PRs](https://github.com/typescript-eslint/typescript-eslint/issues?q=is%3Aissue+is%3Aopen+label%3A%22breaking+change%22) to target the `v${major}` branch.
- To signify these changes as breaking, the first line of the PR description must read as `BREAKING CHANGE:`, and second line should briefly summarize the changes.
- It is important to note that when merged the commit message must also include `BREAKING CHANGE:` as the first line in order for `nx release` to recognize it as a breaking change in the release notes. If you miss this it just means more manual work when writing the release documentation.
1. Write and share out a blog post announcing the new beta [example: [Docs: Blog post describing changes & migration strategy for v5->v6](https://github.com/typescript-eslint/typescript-eslint/issues/6466)].
- Keep this post up-to-date as changes land in the `v${major}` branch.
1. Send a PR to the `v${major}` branch that adds the old major version to [Users > Releases > Old Release Documentation](../users/Releases.mdx#old-release-documentation)
1. Wait until all required PRs have been merged
1. Write a blog post announcing the new release [example: [Docs: Release blog post for v6](https://github.com/typescript-eslint/typescript-eslint/issues/7153)], and land it in the `v${major}` branch.
1. Let the release wait for **at least 1 week** to allow time for early adopters to help test it and discuss the changes.
- Promote it on social media to get some additional attention.
1. Once discussions have settled, traditional merge commit the PR on top of `main` by temporarily enabling that merge setting for the repo.
:::note
_Non_-breaking changes can be merged to `main` or the major branch.
They don't need any special treatment.
:::
### 3. Releasing the Version
1. Discuss with the maintainers to be ready for an [out-of-band](#out-of-band-releases) release. Doing this manually helps ensure someone is on-hand to action any issues that might arise from the major release.
1. Prepare the release notes. `nx release` will automatically generate the release notes on GitHub, however this will be disorganized and unhelpful for users. We need to reorganize the release notes so that breaking changes are placed at the top to make them most visible. If any migrations are required, we must list the steps to make it easy for users.
- Example release notes: [`v6.0.0`](https://github.com/typescript-eslint/typescript-eslint/releases/tag/v6.0.0), [`v5.0.0`](https://github.com/typescript-eslint/typescript-eslint/releases/tag/v5.0.0)
1. Update Netlify deploys for old sites:
1. Update the `CURRENT_MAJOR_VERSION` environment variable to the new major version integer, such as `9`
2. Re-deploy the `v${major}` branches listed in [Users > Releases > Old Release Documentation](../users/Releases.mdx#old-release-documentation)
1. Finally, post the release on social media with a link to the GitHub release. Make sure you include additional information about the highlights of the release!
## Out-of-Band Releases
Per [Users > Releases > Out-of-Band Releases](../users/Releases.mdx#out-of-band-releases), we may manually trigger a new release for a rare emergency such as a critical regression.
If that happens:
1. Mention in any relevant issue(s) that you intend to release an out-of-band release
1. Post in a private maintenance Discord channel that you're working on it
1. Send a pull request resolving the issue(s)
1. Waiting up to a day (as reasonable) for approval before merging the PR
1. Trigger the private release workflow to cause a new release
1. Post back in those same issue(s) with a link to the newly released version(s)
---
# TypeScript ESLint Documentation
# Source: https://raw.githubusercontent.com/typescript-eslint/typescript-eslint/main/docs/maintenance/Team.mdx
# Path: docs/maintenance/Team.mdx
---
id: team
title: Team
---
import { TeamBioDivider } from '@site/src/components/team/TeamBioDivider';
import { TeamBioList } from '@site/src/components/team/TeamBioList';
The typescript-eslint organization is an independent open source project.
Its members are volunteer open source developers dedicated to making the TypeScript linting experience great.
## Maintainers
## Committers
## Join Us
We're always looking for developers to add to the team.
If you're interest in becoming a committer, go ahead and get started with our [Contributing guide](../Contributing.mdx).
[Contributor Tiers](./Contributor_Tiers.mdx) describes the expectations for entering and then staying at any contributor tier.
## Sponsor Us
As an independent open source project, funding for our work comes from the community.
We're eternally grateful to every individual and organization able to help us keep working.
See [`.github/SPONSORSHIPS.md`](https://github.com/typescript-eslint/typescript-eslint/blob/main/.github/SPONSORSHIPS.md) for documentation on how and why to sponsor us.
You can find our biggest sponsors on [typescript-eslint.io > Financial Contributors](/#financial-contributors).
More can be found on [our Open Collective](https://opencollective.com/typescript-eslint).
---
# TypeScript ESLint Documentation
# Source: https://raw.githubusercontent.com/typescript-eslint/typescript-eslint/main/docs/maintenance/issues/Rule_Deprecations_And_Deletions.mdx
# Path: docs/maintenance/issues/Rule_Deprecations_And_Deletions.mdx
---
id: rule-deprecations-and-deletions
title: Rule Deprecations, Renames, And Deletions
---
Sometimes a rule that used to be 👍 does not age well and becomes 👎.
In the past, these cases have included:
- Overly opinionated and/or stylistic rules that don't represent a universal best practice
- Renames
- Rules moved to an external plugin
In these cases, we aim to remove the old rule with minimal user disruption.
## Filing the Issue
Rule deprecations and renames can be filed as a [new issue bypassing templates](https://github.com/typescript-eslint/typescript-eslint/issues/new).
Provide it an `## Overview` containing:
- The rule name & link to its documentation page
- A clear explanation of why you believe it should be deprecated and/or renamed
- Whether it exists in popular configs such as `eslint-config-airbnb-typescript` and `eslint-config-standard-with-typescript`
- Sourcegraph queries showing how often it appears in user configs
> See [#6036](https://github.com/typescript-eslint/typescript-eslint/issues/6036) for examples of those links and queries.
## Timeline
1. In any minor/patch version, add [rule `meta` properties](https://eslint.org/docs/latest/developer-guide/working-with-rules#rule-basics):
- `deprecated: true`
- `replacedBy`, if applicable
2. Search through open issues and PRs, and update the name in them accordingly:
- Deletions: close them with a link to the issue and deprecation PR
- Renames: update their title and explicitly mention in a comment that the rule has been renamed
3. In the next major version, you may delete the deprecated rule
- Leave a documentation page as a tombstone pointing to the new relevant rule or docs (see [`camelcase`](/rules/camelcase) as an example)
---
# TypeScript ESLint Documentation
# Source: https://raw.githubusercontent.com/typescript-eslint/typescript-eslint/main/docs/maintenance/pull-requests/Dependency_Version_Upgrades.mdx
# Path: docs/maintenance/pull-requests/Dependency_Version_Upgrades.mdx
---
id: dependency-version-upgrades
title: Dependency Version Upgrades
---
## Renovate
We rely on [renovate bot](https://github.com/renovatebot/renovate/) to automatically raise PRs to update our dependencies using [this configuration](https://github.com/typescript-eslint/typescript-eslint/blob/main/.github/renovate.json5).
### Dependency Dashboard
Renovate is configured to manage a [dependency dashboard issue](https://github.com/typescript-eslint/typescript-eslint/issues/6687) which can be used to understand the tool's state:
- What dependency bumps require approval for renovate to action (eg because they are major bumps)
- What dependency bumps it is working on (i.e. pending)
- What dependency bumps are currently open and awaiting review + merge
- Note that renovate is an asynchronous tools so this list will lag behind a bit after you merge PRs
- What dependency bumps have been ignored
Ticking a checkbox in this issue will cause renovate to action the dependency:
- If you tick one in the "Pending Approval" list it will approve it and renovate will raise a PR.
- If you tick one in the "Pending Status Checks" list it will cause renovate to create the PR before its internal status checks are complete.
- If you tick one in the "Open" list it will cause renovate to rebase the PR (if there are no manual changes) or recreate the PR (if there are manual changes).
- If you tick one in the "Ignored or Blocked" list it will cause renovate to recreate the PR.
### Merging Renovate PRs
Renovate will not automatically merge its dependency PRs because we have branch protection turned on. Renovate PRs must go through the same workflow as human PRs: i.e. all PRs must be approved with passing status checks before they can be merged.
Renovate will automatically update a PR if there is a conflict with `main`. You can also force it to rebase a PR by ticking the box in the PR's description, or ticking the relevant box on the dependency dashboard.
You should generally avoid clicking the "Update branch" button in the Github UI as this will create a human commit - which cause renovate to treat the branch as "dirty" and it will no longer automatically. Only click it if you are planning on merging the PR manually ASAP.
## Manual Dependency Updates
Occasionally it will be desirable to manually bump the dependencies in one commit rather than relying on renovate's many PRs. Doing so is just a matter of:
1. `git checkout main && git pull`
1. `yarn install`
1. `yarn update-interactive` - this will start yarn's prompt to update the deps.
1. Ignore the lines with `*` deps as these are intentionally set as such.
1. Avoid changing the dep ranges like the complex range we have for TypeScript (eg `>=4.7.4 <5.5.0`).
1. Once you're ready, hit `enter` and yarn will make the changes and rerun the install.
1. Run all of the relevant checks locally so you can action any failures before raising a PR:
1. `yarn build`
1. `yarn typecheck`
1. `yarn lint`
1. `yarn test`
1. `yarn integration-test`
1. Create a new branch (a name like `update-deps-20231201` is good just to keep it unique), create, and land a PR.
### Babel
Our published packages only depend on `@babel/*` packages as devDependencies.
You can generally upgrade those dependencies with:
1. `yarn add -D @babel/code-frame @babel/core @babel/eslint-parser @babel/parser @babel/types`
2. `npx nx run ast-spec:test -u`
The fixtures under `packages/ast-spec/` describe how the files are parsed under both Babel and our (TSESTree) parser.
### ESLint
The typescript-eslint repository contains four kinds of version ranges for the `eslint` package:
- Integration tests: Pinned to our lowest supported ESLint version
- Packages with a `*` `peerDependency` version: These fall back to the explicit `peerDependency` versions
- Packages with explicit `peerDependency` versions: The full range of supported ESLint major versions
- [Root `package.json`](https://github.com/typescript-eslint/typescript-eslint/blob/main/package.json)'s' `devDependency`: A relatively recent release, used only for repository development
:::tip
Whenever you discover any new areas of work that are blocked by dropping an old ESLint version, such as new ESLint API deprecations, add a _TODO_ comment that will be caught by the regular expressions under [Removing Support for an Old ESLint Version](#removing-support-for-an-old-eslint-version).
:::
#### Adding Support for a New ESLint Version
1. Upgrade the root `package.json` `devDependency` to the latest ESLint
1. Add the new major version to the explicit `peerDependency` versions
1. Check [`eslint-visitor-keys`](https://www.npmjs.com/package/eslint-visitor-keys) for a new version to be upgraded to as well.
1. Update [Users > Dependency Versions > ESLint](../../users/Dependency_Versions.mdx#eslint)
#### Removing Support for an Old ESLint Version
1. Increase the integration tests to the next lowest supported major version (`*.0.0`)
1. Remove the old major versions from packages with explicit `peerDependency` versions
1. Search for source code comments (excluding `CHANGELOG.md` files) that mention a now-unsupported version of ESLint.
- For example, to remove support for v5, searches might include:
- `/eslint.*5/i`
- `/todo.*eslint.*5/i`
- `/todo.*eslint/i`
1. Update [Users > Dependency Versions > ESLint](../../users/Dependency_Versions.mdx#eslint)
See [chore: drop support for ESLint v6](https://github.com/typescript-eslint/typescript-eslint/pull/5972) for reference.
### Node
The typescript-eslint repository contains three kinds of version ranges for Node:
- [`.github/workflows/ci.yml`](https://github.com/typescript-eslint/typescript-eslint/blob/main/.github/workflows/ci.yml)'s `PRIMARY_NODE_VERSION`: Set to the highest Node version we support
- `node-version`: Set to a tuple of our `[lowest, highest]` supported versions for our unit tests in CI
- `engines` field in all `package.json`s: explicitly lists all supported Node ranges
Change those numbers accordingly when adding support for a new Node version or removing support for an old Node version.
See [feat: drop support for node v12](https://github.com/typescript-eslint/typescript-eslint/pull/5918) + [chore: test node v14 on ci.yml](https://github.com/typescript-eslint/typescript-eslint/pull/5512) for reference.
### TypeScript
#### Adding Support for a New TypeScript Version
We generally start the process of supporting a new TypeScript version just after the first beta release for that version is made available.
1. Create and pin an issue with a title like _TypeScript X.Y Support_, `accepting prs`, `AST`, `dependencies`, and `New TypeScript Version` labels, and the following contents:
1. A link to the _TypeScript X.Y Iteration Plan_ issue from the Microsoft issue tracker
2. The following text:
```md
This issue is just to track all of the new features and their implementation state in this project.
As with all releases, we will not necessarily support all features until closer to the full release when everything the features are stabilised.
_Please be patient._ ❤️
```
3. A heading starting with `🔲 ` for each new TypeScript feature called out in the iteration plan that will impact us
4. A heading titled _🔲 `lib.d.ts` Updates_ and the content _We will need to regenerate our types within `scope-manager`_
5. A heading titled _Other changes with no impact to us_ containing a list of other changes that we don't believe will impact us
1. At this stage, it's fine to send and/or review PRs that implement necessary features, but wait to merge them until the new TypeScript version's RC is released
- Whenever a PR is created, add ` (#1234)` to its respective heading, and change the heading's emoji from 🔲 to 🏗
- Search for `expectBabelToNotSupport` to see how to support syntaxes not yet supported by Babel
1. Once the TypeScript RC version is released, start merging PRs
- Whenever a PR is merged, change the respective heading's emoji from 🏗 to ✅
1. Create a PR with a title like `feat: update TypeScript to X.Y-rc` and the following changes:
- In the root `package.json`, add `|| X.Y.1-rc2` to the `devDependency` on `typescript`
- In the parser's `getLib`, update the `switch (target)` and its preceding comment as needed (see [#6782](https://github.com/typescript-eslint/typescript-eslint/pull/6782))
- Change the `SUPPORTED_TYPESCRIPT_VERSIONS` constant's `<` version to the next version of TypeScript
- Change the `SUPPORTED_PRERELEASE_RANGES` constant to equal `['X.Y.1-rc']`
- Run `yarn generate-lib` to update `scope-manager`
1. Once all PRs needed for the RC update PR are merged, merge the RC update PR
1. Once TypeScript releases the stable X.Y version, create and merge a PR with a title like `chore: bump TypeScript from X.YRC to X.Y` and the following changes:
- In the root `package.json`, remove `|| X.Y.1-rc2` from the `dependency` on `typescript`, and bump its `<` version to the next version of TypeScript
- In the root `package.json`, change the `resolutions` on `typescript` to `X.Y.3`
- Any other changes made necessary due to changes in TypeScript between the RC version and stable version
1. Send a PR that updates this documentation page to point to your newer issues and PRs
- Also update any of these steps if you go with a different process
See for reference (caveat: these don't follow the exact process described here):
- [TypeScript 4.7 Support](https://github.com/typescript-eslint/typescript-eslint/issues/4800)
- [TypeScript 4.8 Support](https://github.com/typescript-eslint/typescript-eslint/issues/5227)
- [feat: support TypeScript 4.8](https://github.com/typescript-eslint/typescript-eslint/pull/5551)
- [feat: support TypeScript 4.9](https://github.com/typescript-eslint/typescript-eslint/pull/5716)
- [chore: bump TS from 4.9RC to 4.9](https://github.com/typescript-eslint/typescript-eslint/commit/a40a311bb52a2b1cfac43851b201f8cfc96c8d5d)
### Removing Support for an Old TypeScript Version
A single PR can remove support for old TypeScript versions as a breaking change:
1. Update the root `package.json` `devDependency`
1. Update the `SUPPORTED_TYPESCRIPT_VERSIONS` constant in `warnAboutTSVersion.ts`
1. Update the `versions` constant in `version-check.ts`
1. Update [Users > Dependency Versions > TypeScript](../../users/Dependency_Versions.mdx#typescript)
1. Update `MIN_TS_VERSION_SEMVER` in `packages/website/src/components/OptionsSelector.tsx`
1. Search for source code comments (excluding `CHANGELOG.md` files) that mention a now-unsupported version of TypeScript.
- For example, to remove support for v4.3, searches might include:
- `4.3`
- `/is.*4.*3/i`
- `/semver.*4.*3/i`
- `/semver.satisfies/`
- `/todo.*ts/i`
- `/todo.*typescript/i`
See [feat: bump minimum supported TS version to 4.2.4](https://github.com/typescript-eslint/typescript-eslint/pull/5915).
---
# TypeScript ESLint Documentation
# Source: https://raw.githubusercontent.com/typescript-eslint/typescript-eslint/main/docs/packages/ESLint_Plugin.mdx
# Path: docs/packages/ESLint_Plugin.mdx
---
id: eslint-plugin
sidebar_label: eslint-plugin
---
# `@typescript-eslint/eslint-plugin`
> The TypeScript plugin for ESLint. ✨
:::info
See [Getting Started](../getting-started/Quickstart.mdx) for documentation on how to lint your TypeScript code with ESLint.
If you're using ESLint's flat config (`eslint.config.*`), you don't need to install this package or `@typescript-eslint/parser` explicitly.
:::
`@typescript-eslint/eslint-plugin` is an ESLint plugin used to load in custom rules and rule configurations lists from typescript-eslint.
Those rules rely on [`@typescript-eslint/parser`](./Parser.mdx) to parse TypeScript code into ESLint-compatible nodes, as well as provide backing TypeScript programs.
## Exports
| Name | Description |
| --------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `configs` | Object mapping string names of configs to extendable [ESLint config settings](https://eslint.org/docs/latest/user-guide/configuring/configuration-files#extending-configuration-files). |
| `rules` | Object mapping string names of rules to the [rule objects](https://eslint.org/docs/latest/developer-guide/working-with-rules). |
---
# TypeScript ESLint Documentation
# Source: https://raw.githubusercontent.com/typescript-eslint/typescript-eslint/main/docs/packages/ESLint_Plugin_TSLint.mdx
# Path: docs/packages/ESLint_Plugin_TSLint.mdx
---
id: eslint-plugin-tslint
sidebar_label: eslint-plugin-tslint
---
# `@typescript-eslint/eslint-plugin-tslint`
> ESLint plugin that allows running TSLint rules within ESLint to help you migrate from TSLint to ESLint. ✨
:::caution
Per [What About TSLint?](../users/What_About_TSLint.mdx), we highly recommend migrating off TSLint.
See [Getting Started](../getting-started/Quickstart.mdx) for documentation on how to lint your TypeScript code with ESLint.
:::
Documentation for this package has moved to [github.com/typescript-eslint/eslint-plugin-tslint](https://github.com/typescript-eslint/eslint-plugin-tslint).
This page will eventually be removed.
---
# TypeScript ESLint Documentation
# Source: https://raw.githubusercontent.com/typescript-eslint/typescript-eslint/main/docs/packages/Parser.mdx
# Path: docs/packages/Parser.mdx
---
id: parser
sidebar_label: parser
---
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
# `@typescript-eslint/parser`
> An [ESLint parser](https://eslint.org/docs/user-guide/configuring/plugins#specifying-parser) used to parse TypeScript code into ESLint-compatible nodes, as well as provide backing TypeScript programs. ✨
This is necessary because TypeScript produces a different, incompatible AST format to the one that ESLint requires to work.
For example, this is not valid JavaScript code because it contains the `: number` type annotation:
```ts
let x: number = 1;
```
ESLint's native Espree parser would raise an error attempting to parse it.
Additionally, because TypeScript is developed separately and with different goals from ESLint, ESTree, and Espree, its AST also represents nodes differently in many cases.
TS's AST is optimized for its use case of parsing incomplete code and typechecking.
ESTree is unoptimized and intended for "general purpose" use-cases of traversing the AST.
:::tip
You can select `@typescript-eslint/parser` on the [typescript-eslint playground](/play#showAST=es)'s right sidebar by selecting _ESTree_.
:::
## Configuration
The following additional configuration options are available by specifying them in [`parserOptions`](https://eslint.org/docs/user-guide/configuring/language-options#specifying-parser-options) in your ESLint configuration file.
```ts
interface ParserOptions {
cacheLifetime?: {
glob?: number | 'Infinity';
};
disallowAutomaticSingleRunInference?: boolean;
ecmaFeatures?: {
jsx?: boolean;
globalReturn?: boolean;
};
ecmaVersion?: number | 'latest';
emitDecoratorMetadata?: boolean;
experimentalDecorators?: boolean;
isolatedDeclarations?: boolean;
extraFileExtensions?: string[];
jsDocParsingMode?: 'all' | 'none' | 'type-info';
jsxFragmentName?: string | null;
jsxPragma?: string | null;
lib?: string[];
programs?: import('typescript').Program[];
project?: string | string[] | boolean | null;
projectFolderIgnoreList?: string[];
projectService?: boolean | ProjectServiceOptions;
tsconfigRootDir?: string;
warnOnUnsupportedTypeScriptVersion?: boolean;
}
```
### `disallowAutomaticSingleRunInference`
> Default: `process.env.TSESTREE_SINGLE_RUN` or `true`.
Whether to stop using common heuristics to infer whether ESLint is being used as part of a single run (as opposed to `--fix` mode or in a persistent session such as an editor extension).
In other words, typescript-eslint is faster by default, and this option disables an automatic performance optimization.
When typescript-eslint handles TypeScript Program management behind the scenes for [linting with type information](../getting-started/Typed_Linting.mdx), this distinction is important for performance.
There is significant overhead to managing TypeScript "Watch" Programs needed for the long-running use-case.
Being able to assume the single run case allows typescript-eslint to faster immutable Programs instead.
This setting's default value can be specified by setting a `TSESTREE_SINGLE_RUN` environment variable to `"false"` or `"true"`.
For example, `TSESTREE_SINGLE_RUN=false npx eslint .` will disable it.
:::note
We recommend leaving this option off if possible.
We've seen allowing automatic single run inference improve linting speed in CI by up to 10-20%.
:::
### `cacheLifetime`
This option allows you to granularly control our internal cache expiry lengths.
You can specify the number of seconds as an integer number, or the string 'Infinity' if you never want the cache to expire.
By default cache entries will be evicted after 30 seconds, or will persist indefinitely if the parser infers that it is a single run (see [`disallowAutomaticSingleRunInference`](#disallowAutomaticSingleRunInference)).
### `ecmaFeatures`
Optional additional options to describe how to parse the raw syntax.
#### `jsx`
> Default: `false`.
Enable parsing JSX when `true`.
More details can be found in the [TypeScript handbook's JSX docs](https://www.typescriptlang.org/docs/handbook/jsx.html).
**NOTE:** this setting does not affect known file types (`.js`, `.mjs`, `.cjs`, `.jsx`, `.ts`, `.mts`, `.cts`, `.tsx`, `.json`) because the TypeScript compiler has its own internal handling for known file extensions.
{/* https://github.com/microsoft/TypeScript/blob/d6e483b8dabd8fd37c00954c3f2184bb7f1eb90c/src/compiler/utilities.ts#L6281-L6285 */}
The exact behavior is as follows:
- `.js`, `.mjs`, `.cjs`, `.jsx`, `.tsx` files are always parsed as if this is `true`.
- `.ts`, `.mts`, `.cts` files are always parsed as if this is `false`.
- For "unknown" extensions (`.md`, `.vue`):
- If `parserOptions.project` is _not_ provided:
- The setting will be respected.
- If `parserOptions.project` is provided (i.e. you are using rules with type information):
- **always parsed as if this is `false`**
#### `globalReturn`
> Default: `false`.
This options allows you to tell the parser if you want to allow global `return` statements in your codebase.
### `ecmaVersion`
> Default: `2018`.
Accepts any valid ECMAScript version number or `'latest'`:
- A version: es3, es5, es6, es7, es8, es9, es10, es11, es12, es13, ..., or
- A year: es2015, es2016, es2017, es2018, es2019, es2020, es2021, es2022, ..., or
- `'latest'`
When it's a version or a year, the value **must** be a number - so do not include the `es` prefix.
Specifies the version of ECMAScript syntax you want to use. This is used by the parser to determine how to perform scope analysis, and it affects the default
### `emitDecoratorMetadata`
> Default: `undefined`.
This option allow you to tell parser to act as if `emitDecoratorMetadata: true` is set in `tsconfig.json`, but without [type-aware linting](../getting-started/Typed_Linting.mdx). In other words, you don't have to specify `parserOptions.project` in this case, making the linting process faster.
### `experimentalDecorators`
> Default: `undefined`.
This option allow you to tell parser to act as if `experimentalDecorators: true` is set in `tsconfig.json`, but without [type-aware linting](../getting-started/Typed_Linting.mdx). In other words, you don't have to specify `parserOptions.project` in this case, making the linting process faster.
### `extraFileExtensions`
> Default: `undefined`.
This option allows you to provide one or more additional file extensions which should be considered in the TypeScript Program compilation.
The default extensions are `['.js', '.mjs', '.cjs', '.jsx', '.ts', '.mts', '.cts', '.tsx']`.
Add extensions starting with `.`, followed by the file extension. E.g. for a `.vue` file use `"extraFileExtensions": [".vue"]`.
:::note
See [Changes to `extraFileExtensions` with `projectService`](../troubleshooting/typed-linting/Performance.mdx#changes-to-extrafileextensions-with-projectservice) to avoid performance issues.
:::
### `isolatedDeclarations`
> Default: `undefined`.
This option allow you to tell parser to act as if `isolatedDeclarations: true` is set in `tsconfig.json`, but without [type-aware linting](../getting-started/Typed_Linting.mdx).
In other words, you don't have to specify `parserOptions.project` in this case, making the linting process faster.
### `jsDocParsingMode`
> Default if `parserOptions.project` is set, then `'all'`, otherwise `'none'`
When TS parses a file it will also parse JSDoc comments into the AST - which can then be consumed by lint rules.
If you are using TypeScript version >=5.3 then this option can be used as a performance optimization.
The valid values for this rule are:
- `'all'` - parse all JSDoc comments, always.
- `'none'` - parse no JSDoc comments, ever.
- `'type-info'` - parse just JSDoc comments that are required to provide correct type-info. TS will always parse JSDoc in non-TS files, but never in TS files.
If you do not use lint rules like `eslint-plugin-deprecation` that rely on TS's JSDoc tag representation, then you can set this to `'none'` to improve parser performance.
### `jsxFragmentName`
> Default: `null`
The identifier that's used for JSX fragment elements (after transpilation).
If `null`, assumes transpilation will always use a member of the configured `jsxPragma`.
This should not be a member expression - just the root identifier (i.e. use `"h"` instead of `"h.Fragment"`).
If you provide `parserOptions.project`, you do not need to set this, as it will be automatically detected from the compiler.
### `jsxPragma`
> Default: `'React'`
The identifier that's used for JSX Elements creation (after transpilation).
If you're using a library other than React (like `preact`), then you should change this value. If you are using the [new JSX transform](https://reactjs.org/blog/2020/09/22/introducing-the-new-jsx-transform.html) you can set this to `null`.
This should not be a member expression - just the root identifier (i.e. use `"React"` instead of `"React.createElement"`).
If you provide `parserOptions.project`, you do not need to set this, as it will be automatically detected from the compiler.
### `lib`
> Default: `['es2018']`
For valid options, see the [TypeScript compiler options](https://www.typescriptlang.org/tsconfig#lib).
Specifies the TypeScript `lib`s that are available. This is used by the scope analyser to ensure there are global variables declared for the types exposed by TypeScript.
If you provide `parserOptions.project`, you do not need to set this, as it will be automatically detected from the compiler.
### `programs`
> Default: `undefined`.
This option allows you to programmatically provide an instance of a TypeScript Program object that will provide type information to rules.
This will override any programs that would have been computed from `parserOptions.project`.
All linted files must be part of the provided program(s).
[Refer to the TypeScript Wiki for an example on how to write the `resolveModuleNames` function](https://github.com/Microsoft/TypeScript/wiki/Using-the-Compiler-API#customizing-module-resolution).
### `project`
:::note
We now recommend using [`projectService`](#projectservice) instead of `project` for easier configuration and faster linting.
:::
> Default: `undefined`.
A path to your project's TSConfig. **This setting or [`projectService`](#projectservice) are required to use [rules which require type information](../getting-started/Typed_Linting.mdx)**.
Accepted value types:
```js
// find the tsconfig.json nearest to each source file
project: true,
// path
project: './tsconfig.json';
// glob pattern
project: './packages/**/tsconfig.json';
// array of paths and/or glob patterns
project: ['./packages/**/tsconfig.json', './separate-package/tsconfig.json'];
// ways to disable type-aware linting (useful for overrides configs)
project: false;
project: null;
```
- If `true`, each source file's parse will find the nearest `tsconfig.json` file to that source file.
- This is done by checking that source file's directory tree for the nearest `tsconfig.json`.
- If you use project references, TypeScript will **not** automatically use project references to resolve files. This means that you will have to add each referenced tsconfig to the `project` field either separately, or via a glob.
- Note that using wide globs `**` in your `parserOptions.project` may cause performance implications. Instead of globs that use `**` to recursively check all folders, prefer paths that use a single `*` at a time. For more info see [#2611](https://github.com/typescript-eslint/typescript-eslint/issues/2611).
- TypeScript will ignore files with duplicate filenames in the same folder (for example, `src/file.ts` and `src/file.js`). TypeScript purposely ignores all but one of the files, only keeping the one file with the highest priority extension (the extension priority order (from highest to lowest) is `.ts`, `.tsx`, `.d.ts`, `.js`, `.jsx`). For more info see [#955](https://github.com/typescript-eslint/typescript-eslint/issues/955).
:::note
Relative paths are interpreted relative to the current working directory if [`tsconfigRootDir`](#tsconfigrootdir) is not set.
:::
If this setting is specified, you must only lint files that are included in the projects as defined by the provided TSConfig file(s). If your existing configuration does not include all of the files you would like to lint, you can create a separate `tsconfig.eslint.json` as follows:
```jsonc
{
// extend your base config so you don't have to redefine your compilerOptions
"extends": "./tsconfig.json",
"include": [
"src/**/*.ts",
"test/**/*.ts",
"typings/**/*.ts",
// etc
// if you have a mixed JS/TS codebase, don't forget to include your JS files
"src/**/*.js",
],
}
```
For an option that allows linting files outside of your TSConfig file(s), see [`projectService`](#projectservice).
#### Usage with `projectService`
Enabling both `project` and `projectService` at the same time will cause an error:
> ```plaintext
> Enabling "project" does nothing when "projectService" is enabled. You can remove the "project" setting
> ```
If you're enabling `projectService`, we generally recommend disabling `project`.
However, if you need, you can disable this check with a `TYPESCRIPT_ESLINT_IGNORE_PROJECT_AND_PROJECT_SERVICE_ERROR` environment variable:
```shell
TYPESCRIPT_ESLINT_IGNORE_PROJECT_AND_PROJECT_SERVICE_ERROR=true npx eslint .
```
### `projectService`
> Default: `false`.
Specifies using TypeScript APIs to generate type information for rules.
It will automatically use the nearest `tsconfig.json` for each file (like `project: true`).
It can also be configured to also allow type information to be computed for JavaScript files without the `allowJs` compiler option (unlike `project: true`).
See [Typed Linting with `parserOptions.projectService`](/blog/project-service) for more context.
```js title="eslint.config.js"
export default [
{
languageOptions: {
parserOptions: {
projectService: true,
},
},
},
];
```
```js title=".eslintrc.js"
module.exports = {
parser: '@typescript-eslint/parser',
parserOptions: {
projectService: true,
},
};
```
**This setting or [`project`](#project) are required to use [rules which require type information](../getting-started/Typed_Linting.mdx)**.
This option brings two main benefits over the older `project`:
- Simpler configurations: most projects shouldn't need to explicitly configure `project` paths or create `tsconfig.eslint.json`s
- Predictability: it uses the same type information services as editors, giving better consistency with the types seen in editors
See [FAQs > Typed Linting > Project Service Issues](../troubleshooting/typed-linting/index.mdx#project-service-issues) for help on working with the project service.
#### `ProjectServiceOptions`
The behavior of `parserOptions.projectService` can be customized by setting it to an object.
```js
{
parser: '@typescript-eslint/parser',
parserOptions: {
projectService: {
allowDefaultProject: ['*.js'],
},
},
};
```
:::tip
See [Troubleshooting & FAQs > Typed Linting > Project Service Issues](../troubleshooting/typed-linting/index.mdx#project-service-issues) for help using these options.
:::
##### `allowDefaultProject`
> Default: `[]` _(none)_
Globs of files to allow running with the default project compiler options despite not being matched by the project service.
It takes in an array of string paths that will be resolved relative to the [`tsconfigRootDir`](#tsconfigrootdir).
This is intended to produce type information for config files such as `eslint.config.js` that aren't included in their sibling `tsconfig.json`.
Every file with type information retrieved from the default project incurs a non-trivial performance overhead to linting.
Use this option sparingly.
There are several restrictions on this option to prevent it from being overused:
- `**` is not allowed in globs passed to it
- Files that match `allowDefaultProject` may not also be included in their nearest `tsconfig.json`
##### `defaultProject`
> Default: `'tsconfig.json'`
Path to a TSConfig to use instead of TypeScript's default project configuration.
It takes in a string path that will be resolved relative to the [`tsconfigRootDir`](#tsconfigrootdir).
`projectService.defaultProject` only impacts the "out-of-project" files included by [`allowDefaultProject`](#allowdefaultproject).
##### `loadTypeScriptPlugins`
> Default: `false`
Whether the project service should be allowed to load [TypeScript plugins](https://www.typescriptlang.org/tsconfig/plugins.html).
This is `false` by default to prevent plugins from registering persistent file watchers or other operations that might prevent ESLint processes from exiting when run on the command-line.
If your project is configured with custom rules that interact with TypeScript plugins, it may be useful to turn this on in your editor.
For example, only enabling this option when running within VS Code:
```js
parserOptions: {
projectService: {
loadTypeScriptPlugins: !!process.env.VSCODE_PID,
}
}
```
##### `maximumDefaultProjectFileMatchCount_THIS_WILL_SLOW_DOWN_LINTING`
> Default: `8`.
The maximum number of files [`allowDefaultProject`](#allowdefaultproject) may match.
Each file match slows down linting, so if you do need to use this, please file an informative issue on typescript-eslint explaining why - so we can help you avoid using it!
### `projectFolderIgnoreList`
> Default: `["**/node_modules/**"]`.
This option allows you to ignore folders from being included in your provided list of `project`s.
This is useful if you have configured glob patterns, but want to make sure you ignore certain folders.
It accepts an array of globs to exclude from the `project` globs.
For example, by default it will ensure that a glob like `./**/tsconfig.json` will not match any `tsconfig`s within your `node_modules` folder (some npm packages do not exclude their source files from their published packages).
### `tsconfigRootDir`
> Default: the directory of the ESLint config file.
This option allows you to provide the root directory for relative TSConfig paths specified in the [`project`](#project) and [`projectService`](#projectservice) options.
Doing so ensures running ESLint from a directory other than the root will still be able to find your TSConfig.
`tsconfigRootDir` uses the call stack to determine the closest `eslint.config.*` ESLint config file.
In rare edge cases, that detection logic may be tricked by unusual paths and resolve to an incorrect value.
Manually specifying `tsconfigRootDir` to the directory of your ESLint config file will work around those issues:
```js
parserOptions: {
projectService: true,
tsconfigRootDir: import.meta.dirname,
// or, in CommonJS, __dirname
}
```
### `warnOnUnsupportedTypeScriptVersion`
> Default: `true`.
This option allows you to toggle the warning that the parser will give you if you use a version of TypeScript which is not explicitly supported. The warning message would look like this:
```plaintext
=============
WARNING: You are currently running a version of TypeScript which is not officially supported by @typescript-eslint/typescript-estree.
* @typescript-eslint/typescript-estree version: 8.15.0
* Supported TypeScript versions: >=4.7.4 <5.7.0
* Your TypeScript version: 5.7.1
Please only submit bug reports when using the officially supported version.
=============
```
## Utilities
### `createProgram(configFile, projectDirectory)`
This serves as a utility method for users of the `parserOptions.programs` feature to create a TypeScript program instance from a config file.
```ts
declare function createProgram(
configFile: string,
projectDirectory?: string,
): import('typescript').Program;
```
Example usage:
```js title="eslint.config.mjs"
import * as parser from '@typescript-eslint/parser';
export default [
{
parserOptions: {
programs: [parser.createProgram('tsconfig.json')],
},
},
];
```
```js title=".eslintrc.js"
const parser = require('@typescript-eslint/parser');
module.exports = {
parserOptions: {
programs: [parser.createProgram('tsconfig.json')],
},
};
```
### `withoutProjectParserOptions(parserOptions)`
Removes options that prompt the parser to parse the project with type information.
In other words, you can use this if you are invoking the parser directly, to ensure that one file will be parsed in isolation, which is much faster.
This is useful in cases where you invoke the parser directly, such as in an ESLint plugin context.
```ts
declare function withoutProjectParserOptions(
options: TSESTreeOptions,
): TSESTreeOptions;
```
Example usage:
```js title="somePlugin.js"
const parser = require('@typescript-eslint/parser');
function parse(path, content, context) {
const contextParserOptions = context.languageOptions?.parserOptions ?? {};
const parserOptions =
parser.withoutProjectParserOptions(contextParserOptions);
// Do something with the cleaned-up options eventually, such as invoking the parser
parser.parseForESLint(content, parserOptions);
}
```
---
# TypeScript ESLint Documentation
# Source: https://raw.githubusercontent.com/typescript-eslint/typescript-eslint/main/docs/packages/Project_Service.mdx
# Path: docs/packages/Project_Service.mdx
---
id: project-service
sidebar_label: project-service
toc_max_heading_level: 3
---
import GeneratedDocs from './project-service/generated/index.md';
# `@typescript-eslint/project-service`
> Standalone TypeScript project service wrapper for linting ✨
The typescript-eslint Project Service is a wrapper around TypeScript's "project service" APIs.
These APIs are what editors such as VS Code use to programmatically "open" files and generate TypeScript programs for type information.
:::note
See [Blog > Typed Linting with Project Service](/blog/project-service) for more details on how lint users interact with the Project Service.
:::
```ts
import { createProjectService } from '@typescript-eslint/project-service';
const filePathAbsolute = '/path/to/your/project/index.ts';
const { service } = createProjectService();
service.openClientFile(filePathAbsolute);
const scriptInfo = service.getScriptInfo(filePathAbsolute)!;
const program = service
.getDefaultProjectForFile(scriptInfo.fileName, true)!
.getLanguageService(true)
.getProgram()!;
```
The following documentation is auto-generated from source code.
---
# TypeScript ESLint Documentation
# Source: https://raw.githubusercontent.com/typescript-eslint/typescript-eslint/main/docs/packages/RuleSchemaToTypeScriptTypes.mdx
# Path: docs/packages/RuleSchemaToTypeScriptTypes.mdx
---
id: rule-schema-to-typescript-types
sidebar_label: rule-schema-to-typescript-types
toc_max_heading_level: 3
---
import GeneratedDocs from './rule-schema-to-typescript-types/generated/index.md';
# `@typescript-eslint/rule-schema-to-typescript-types`
> Converts ESLint rule schemas to equivalent TypeScript type strings ✨
```ts
import { schemaToTypes } from '@typescript-eslint/rule-schema-to-typescript-types';
// "
// type Options = [
// /** My great option! */
// string[]
// ];
// "
schemaToTypes({
description: 'My great option!',
items: { type: 'string' },
type: 'array',
});
```
The following documentation is auto-generated from source code.
---
# TypeScript ESLint Documentation
# Source: https://raw.githubusercontent.com/typescript-eslint/typescript-eslint/main/docs/packages/Rule_Tester.mdx
# Path: docs/packages/Rule_Tester.mdx
---
id: rule-tester
sidebar_label: rule-tester
---
import CodeBlock from '@theme/CodeBlock';
# `@typescript-eslint/rule-tester`
> A utility for testing ESLint rules
This is a fork of ESLint's built-in `RuleTester` to provide some better types and additional features for testing TypeScript rules.
## Usage
For non-type-aware rules you can test them as follows:
```ts
import { RuleTester } from '@typescript-eslint/rule-tester';
import rule from '../src/rules/my-rule.ts';
const ruleTester = new RuleTester();
ruleTester.run('my-rule', rule, {
valid: [
// valid tests can be a raw string,
'const x = 1;',
// or they can be an object
{
code: 'const y = 2;',
options: [{ ruleOption: true }],
},
// you can enable JSX parsing by passing parserOptions.ecmaFeatures.jsx = true
{
code: 'const z = ;',
languageOptions: {
parserOptions: {
ecmaFeatures: {
jsx: true,
},
},
},
},
],
invalid: [
// invalid tests must always be an object
{
code: 'const a = 1;',
// invalid tests must always specify the expected errors
errors: [
{
messageId: 'ruleMessage',
// If applicable - it's recommended that you also assert the data in
// addition to the messageId so that you can ensure the correct message
// is generated
data: {
placeholder1: 'a',
},
},
],
},
// fixers can be tested using the output parameter
{
code: 'const b = 1;',
output: 'const c = 1;',
errors: [
/* ... */
],
},
// passing `output = null` will enforce the code is NOT changed
{
code: 'const c = 1;',
output: null,
errors: [
/* ... */
],
},
// Multi-pass fixes can be tested using the array form of output.
// Note: this is unique to typescript-eslint, and doesn't exist in ESLint core.
{
code: 'const d = 1;',
output: ['const e = 1;', 'const f = 1;'],
errors: [
/* ... */
],
},
// suggestions can be tested via errors
{
code: 'const d = 1;',
output: null,
errors: [
{
messageId: 'suggestionError',
suggestions: [
{
messageId: 'suggestionOne',
output: 'const e = 1;',
},
],
},
],
},
// passing `suggestions = null` will enforce there are NO suggestions
{
code: 'const d = 1;',
output: null,
errors: [
{
messageId: 'noSuggestionError',
suggestions: null,
},
],
},
],
});
```
### Type-Aware Testing
Type-aware rules can be tested in almost exactly the same way as regular code, using `parserOptions.projectService`.
Most rule tests specify `parserOptions.allowDefaultProject: ["*.ts*"]` to enable type checking on all test files.
You can then test your rule by providing the type-aware config:
```ts
const ruleTester = new RuleTester({
// Added lines start
languageOptions: {
parserOptions: {
projectService: {
allowDefaultProject: ['*.ts*'],
},
tsconfigRootDir: './path/to/your/folder/fixture',
},
},
// Added lines end
});
```
With that config the parser will automatically run in type-aware mode and you can write tests just like before.
When not specified with a `filename` option, `RuleTester` uses the following test file names:
- `file.ts`: by default
- `react.tsx`: if `parserOptions.ecmaFeatures.jsx` is enabled
### Test Dependency Constraints
Sometimes it's desirable to test your rule against multiple versions of a dependency to ensure backwards and forwards compatibility.
With backwards-compatibility testing there comes a complication in that some tests may not be compatible with an older version of a dependency.
For example - if you're testing against an older version of TypeScript, certain features might cause a parser error!
import DependencyConstraint from '!!raw-loader!../../packages/rule-tester/src/types/DependencyConstraint.ts';
{DependencyConstraint}
The `RuleTester` allows you to apply dependency constraints at either an individual test or constructor level.
```ts
const ruleTester = new RuleTester({
// Added lines start
dependencyConstraints: {
// none of the tests will run unless `my-dependency` matches the semver range `>=1.2.3`
'my-dependency': '1.2.3',
// you can also provide granular semver ranges
'my-granular-dep': {
// none of the tests will run unless `my-granular-dep` matches the semver range `~3.2.1`
range: '~3.2.1',
},
},
// Added lines end
});
ruleTester.run('my-rule', rule, {
valid: [
{
code: 'const y = 2;',
// Added lines start
dependencyConstraints: {
// this test won't run unless BOTH dependencies match the given ranges
first: '1.2.3',
second: '3.2.1',
},
// Added lines end
},
],
invalid: [
/* ... */
],
});
```
All dependencies provided in the `dependencyConstraints` object must match their given ranges in order for a test to not be skipped.
### With Specific Frameworks
ESLint's `RuleTester` relies on some global hooks for tests.
If they aren't available globally, your tests will fail with an error like:
> ```plaintext
> Error: Missing definition for `afterAll` - you must set one using `RuleTester.afterAll` or there must be one defined globally as `afterAll`.
> ```
:::tip
Be sure to set `RuleTester`'s static properties _before_ calling `new RuleTester(...)` for the first time.
:::
#### Mocha
Consider setting up `RuleTester`'s static properties in a [`mochaGlobalSetup` fixture](https://mochajs.org/#global-setup-fixtures):
```ts
import * as mocha from 'mocha';
import { RuleTester } from '@typescript-eslint/rule-tester';
RuleTester.afterAll = mocha.after;
```
#### Node.js (`node:test`)
Consider setting up `RuleTester`'s static properties in a preloaded module using the [`--import`](https://nodejs.org/api/cli.html#--importmodule) or [`--require`](https://nodejs.org/api/cli.html#-r---require-module) flag:
```ts
// setup.js
import * as test from 'node:test';
import { RuleTester } from '@typescript-eslint/rule-tester';
RuleTester.afterAll = test.after;
RuleTester.describe = test.describe;
RuleTester.it = test.it;
RuleTester.itOnly = test.it.only;
```
Tests can then be [run from the command line](https://nodejs.org/api/test.html#running-tests-from-the-command-line) like so:
```sh
node --import setup.js --test
```
#### Vitest
Consider setting up `RuleTester`'s static properties in a [`setupFiles` script](https://vitest.dev/config/#setupfiles):
```ts
import * as vitest from 'vitest';
import { RuleTester } from '@typescript-eslint/rule-tester';
RuleTester.afterAll = vitest.afterAll;
// If you are not using vitest with globals: true (https://vitest.dev/config/#globals):
RuleTester.it = vitest.it;
RuleTester.itOnly = vitest.it.only;
RuleTester.describe = vitest.describe;
```
#### Other Frameworks
In general, `RuleTester` can support any test framework that exposes hooks for running code before or after rules.
From `RuleTester`'s [Static Properties](#static-properties), assign any of the following that the running test framework supports.
- `afterAll`
- `describe`
- `it`
- `itOnly`
I.e.:
```ts
import * as test from '...';
import { RuleTester } from '@typescript-eslint/rule-tester';
RuleTester.afterAll = test.after;
RuleTester.describe = test.describe;
RuleTester.it = test.it;
RuleTester.itOnly = test.it.only;
```
## Options
### `RuleTester` constructor options
import RuleTesterConfig from '!!raw-loader!../../packages/rule-tester/src/types/RuleTesterConfig.ts';
{RuleTesterConfig}
### Valid test case options
import ValidTestCase from '!!raw-loader!../../packages/rule-tester/src/types/ValidTestCase.ts';
{ValidTestCase}
### Invalid test case options
import InvalidTestCase from '!!raw-loader!../../packages/rule-tester/src/types/InvalidTestCase.ts';
{InvalidTestCase}
## Static Properties
Each of the following properties may be assigned to as static members of the `RuleTester` class.
For example, to assign `afterAll`:
```ts
import { RuleTester } from '@typescript-eslint/rule-tester';
RuleTester.afterAll = () => {
// ...
};
```
### `afterAll`
Runs after all the tests in this file have completed.
### `describe`
Creates a test grouping.
### `describeSkip`
Skips running the tests inside this `describe`.
### `it`
Creates a test closure.
### `itOnly`
Skips all other tests in the current file.
### `itSkip`
Skips running this test.
---
# TypeScript ESLint Documentation
# Source: https://raw.githubusercontent.com/typescript-eslint/typescript-eslint/main/docs/packages/Scope_Manager.mdx
# Path: docs/packages/Scope_Manager.mdx
---
id: scope-manager
sidebar_label: scope-manager
---
# `@typescript-eslint/scope-manager`
> A fork of [`eslint-scope`](https://github.com/eslint/eslint-scope), enhanced to support TypeScript functionality. ✨
A "scope analyser" traverses an AST and builds a model of how variables (and in our case, types) are defined and consumed by the source code.
This form of static analysis allows you to understand and trace variables throughout the program, allowing you to access powerful information about a program without needing to drop into the much, much heavier type information.
## API
### `analyze(tree, options)`
Analyses a given AST and returns the resulting `ScopeManager`.
```ts
interface AnalyzeOptions {
/**
* Known visitor keys.
*/
childVisitorKeys?: Record | null;
/**
* Whether the whole script is executed under node.js environment.
* When enabled, the scope manager adds a function scope immediately following the global scope.
* Defaults to `false`.
*/
globalReturn?: boolean;
/**
* Implied strict mode.
* Defaults to `false`.
*/
impliedStrict?: boolean;
/**
* The identifier that's used for JSX Element creation (after transpilation).
* This should not be a member expression - just the root identifier (i.e. use "React" instead of "React.createElement").
* Defaults to `"React"`.
*/
jsxPragma?: string;
/**
* The identifier that's used for JSX fragment elements (after transpilation).
* If `null`, assumes transpilation will always use a member on `jsxFactory` (i.e. React.Fragment).
* This should not be a member expression - just the root identifier (i.e. use "h" instead of "h.Fragment").
* Defaults to `null`.
*/
jsxFragmentName?: string | null;
/**
* The lib used by the project.
* This automatically defines a type variable for any types provided by the configured TS libs.
* For more information, see https://www.typescriptlang.org/tsconfig#lib
*
* Defaults to ['esnext'].
*/
lib?: Lib[];
/**
* The source type of the script.
*/
sourceType?: 'script' | 'module';
/**
* Emit design-type metadata for decorated declarations in source.
* Defaults to `false`.
*/
emitDecoratorMetadata?: boolean;
}
```
Example usage:
```ts
import { analyze } from '@typescript-eslint/scope-manager';
import { parse } from '@typescript-eslint/typescript-estree';
const code = `const hello: string = 'world';`;
const ast = parse(code, {
// note that scope-manager requires ranges on the AST
range: true,
});
const scope = analyze(ast, {
sourceType: 'module',
});
```
## References
- [You can view the original BSD 2 license for the code here](https://github.com/eslint/eslint-scope/blob/dbddf14d5771b21b5da704213e4508c660ca1c64/LICENSE)
- https://eslint.org/docs/developer-guide/scope-manager-interface
- https://github.com/eslint/eslint-scope
---
# TypeScript ESLint Documentation
# Source: https://raw.githubusercontent.com/typescript-eslint/typescript-eslint/main/docs/packages/TSConfig_Utils.mdx
# Path: docs/packages/TSConfig_Utils.mdx
---
id: tsconfig-utils
sidebar_label: tsconfig-utils
toc_max_heading_level: 3
---
import GeneratedDocs from './tsconfig-utils/generated/index.md';
# `@typescript-eslint/tsconfig-utils`
> Utilities for collecting TSConfigs for linting scenarios ✨
The following documentation is auto-generated from source code.
---
# TypeScript ESLint Documentation
# Source: https://raw.githubusercontent.com/typescript-eslint/typescript-eslint/main/docs/packages/TypeScript_ESLint.mdx
# Path: docs/packages/TypeScript_ESLint.mdx
---
id: typescript-eslint
sidebar_label: typescript-eslint
---
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
# `typescript-eslint`
> Tooling which enables you to use TypeScript with ESLint
This package is the main entrypoint that you can use to consume our tooling with ESLint.
This package exports the following:
| 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) |
| `FlatConfig` | A re-export of the type from [`@typescript-eslint/utils`](./Utils.mdx) |
## Installation
```bash npm2yarn
npm i typescript-eslint
```
## Usage
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 defineConfig(
eslint.configs.recommended,
tseslint.configs.recommended,
);
```
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).
### `config(...)` (deprecated)
:::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.
:::
`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.
By using this function you will get autocomplete and documentation for all config properties.
Additionally, if you provide invalid values, it can trigger informative TypeScript type errors.
```ts title="eslint.config.mjs"
// @ts-check
import eslint from '@eslint/js';
import tseslint from 'typescript-eslint';
export default tseslint.config(
eslint.configs.recommended,
tseslint.configs.recommended,
{
/*... */
},
// ...
);
```
```ts title="eslint.config.mjs"
// @ts-check
import eslint from '@eslint/js';
import tseslint from 'typescript-eslint';
/** @type {import('@typescript-eslint/utils').TSESLint.FlatConfig.ConfigFile} */
export default [
eslint.configs.recommended,
...tseslint.configs.recommended,
{
/*... */
},
// ...
];
```
:::note
We _**strongly**_ recommend using this utility to improve the config authoring experience — however it is entirely optional.
By choosing not to use it you lose editor autocomplete and type checking for config files.
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.
This allows you to more easily extend shared configs for specific file patterns whilst also overriding rules/options provided by those configs:
```js
export default tseslint.config({
files: ['**/*.ts'],
extends: [
eslint.configs.recommended,
tseslint.configs.recommended,
],
rules: {
'@typescript-eslint/array-type': 'error',
// ...
},
});
// is the same as writing
export default [
...[
eslint.configs.recommended,
...tseslint.configs.recommended,
].map(conf => ({
...conf,
files: ['**/*.ts'],
})),
{
files: ['**/*.ts'],
rules: {
'@typescript-eslint/array-type': 'error',
// ...
},
},
];
```
We found that this is a common operation when writing ESLint configs which is why we provided this convenience property.
For example, in codebases with type-aware linting, a config object like the following is a common way to disable TypeScript-specific linting setups on JavaScript files:
```js
export default tseslint.config({
files: ['**/*.js'],
extends: [tseslint.configs.disableTypeChecked],
rules: {
// turn off other type-aware rules
'other-plugin/typed-rule': 'off',
// turn off rules that don't apply to JS code
'@typescript-eslint/explicit-function-return-type': 'off',
},
});
```
#### 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/Shared_Configurations.mdx) specify typescript-eslint `parser` and `plugin` options for you, so there is no need to manually provide those.
However, in complex ESLint configurations, you may find yourself manually specifying those options yourself.
#### Manually configuring our plugin and parser
You can declare our plugin and parser in your config via this package, for example:
```js title="eslint.config.mjs"
// @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 defineConfig({
plugins: {
// highlight-next-line
'@typescript-eslint': tseslint.plugin,
},
languageOptions: {
// highlight-next-line
parser: tseslint.parser,
parserOptions: {
projectService: true,
},
},
rules: {
'@typescript-eslint/no-floating-promises': 'error',
// ...
},
});
```
:::warning
We **_strongly_** recommend declaring our plugin with the namespace `@typescript-eslint` as shown above.
If you use our shared configs this is the namespace that they use.
This has been the standard namespace for our plugin for many years and is what users are most familiar with.
You may choose a different namespace - but note that currently [flat configs allow the same plugin to be registered, configured, and have duplicate reports under multiple namespaces](https://github.com/eslint/eslint/discussions/17766).
:::
### Usage with other plugins
Below is a more complex example of how you might use our tooling with flat configs.
This config:
- Ignores `build`/`dist` folders from being linted
- Enables our plugin, our parser, and type-aware linting with a few of our popular type-aware rules
- Disables type-aware linting on JS files
- Enables the recommended `eslint-plugin-jest` rules on test files only
```js title="eslint.config.mjs"
// @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 defineConfig(
{
// config with just ignores is the replacement for `.eslintignore`
ignores: ['**/build/**', '**/dist/**', 'src/some/file/to/ignore.ts'],
},
eslint.configs.recommended,
{
plugins: {
'@typescript-eslint': tseslint.plugin,
jest: jestPlugin,
},
languageOptions: {
parser: tseslint.parser,
parserOptions: {
projectService: true,
},
},
rules: {
'@typescript-eslint/no-floating-promises': 'error',
// ...
},
},
{
// disable type-aware linting on JS files
files: ['**/*.js'],
extends: [tseslint.configs.disableTypeChecked],
},
{
// enable jest rules on test files
files: ['test/**'],
extends: [jestPlugin.configs['flat/recommended']],
},
);
```
## Migrating from legacy `.eslintrc` configs
If you're migrating from a legacy `.eslintrc` configuration setup you likely have our plugin and parser installed separately.
This package includes these as dependencies so you can freely uninstall your local references:
```bash npm2yarn
npm un @typescript-eslint/parser @typescript-eslint/eslint-plugin
```
For more information on migrating from a "legacy" config setup, see [ESLint's Configuration Migration Guide](https://eslint.org/docs/latest/use/configure/migration-guide).
---
# TypeScript ESLint Documentation
# Source: https://raw.githubusercontent.com/typescript-eslint/typescript-eslint/main/docs/packages/TypeScript_ESTree.mdx
# Path: docs/packages/TypeScript_ESTree.mdx
---
id: typescript-estree
sidebar_label: typescript-estree
---
# `@typescript-eslint/typescript-estree`
> The underlying code used by [`@typescript-eslint/parser`](./Parser.mdx) that converts TypeScript source code into an ESTree-compatible form. ✨
This parser is designed to be generic and robust.
It can be used to power any use-case which requires taking TypeScript source code and producing an ESTree-compatible AST.
It is most known for use within these hyper-popular open-source projects to power their TypeScript support:
- [ESLint](https://eslint.org), the pluggable linting utility for JavaScript and JSX
- [Prettier](https://prettier.io), an opinionated code formatter
It works by:
1. Invoking the TypeScript compiler on the given source code in order to
produce a TypeScript AST
2. Converting that TypeScript AST into an ESTree AST
## API
### Parsing
#### `parse(code, options)`
Parses the given string of code with the options provided and returns an ESTree-compatible AST.
```ts
interface ParseOptions {
/**
* Specify the `sourceType`.
* For more details, see https://github.com/typescript-eslint/typescript-eslint/pull/9121
*/
sourceType?: SourceType;
/**
* Prevents the parser from throwing an error if it receives an invalid AST from TypeScript.
* This case only usually occurs when attempting to lint invalid code.
*/
allowInvalidAST?: boolean;
/**
* create a top-level comments array containing all comments
*/
comment?: boolean;
/**
* Whether deprecated AST properties should skip calling console.warn on accesses.
*/
suppressDeprecatedPropertyWarnings?: boolean;
/**
* An array of modules to turn explicit debugging on for.
* - 'typescript-eslint' is the same as setting the env var `DEBUG=typescript-eslint:*`
* - 'eslint' is the same as setting the env var `DEBUG=eslint:*`
* - 'typescript' is the same as setting `extendedDiagnostics: true` in your tsconfig compilerOptions
*
* For convenience, also supports a boolean:
* - true === ['typescript-eslint']
* - false === []
*/
debugLevel?: boolean | ('typescript-eslint' | 'eslint' | 'typescript')[];
/**
* Cause the parser to error if it encounters an unknown AST node type (useful for testing).
* This case only usually occurs when TypeScript releases new features.
*/
errorOnUnknownASTType?: boolean;
/**
* Absolute (or relative to `cwd`) path to the file being parsed.
*/
filePath?: string;
/**
* If you are using TypeScript version >=5.3 then this option can be used as a performance optimization.
*
* The valid values for this rule are:
* - `'all'` - parse all JSDoc comments, always.
* - `'none'` - parse no JSDoc comments, ever.
* - `'type-info'` - parse just JSDoc comments that are required to provide correct type-info. TS will always parse JSDoc in non-TS files, but never in TS files.
*
* If you do not rely on JSDoc tags from the TypeScript AST, then you can safely set this to `'none'` to improve performance.
*/
jsDocParsingMode?: JSDocParsingMode;
/**
* Enable parsing of JSX.
* For more details, see https://www.typescriptlang.org/docs/handbook/jsx.html
*
* NOTE: this setting does not effect known file types (.js, .cjs, .mjs, .jsx, .ts, .mts, .cts, .tsx, .json) because the
* TypeScript compiler has its own internal handling for known file extensions.
*
* For the exact behavior, see https://github.com/typescript-eslint/typescript-eslint/tree/main/packages/parser#parseroptionsecmafeaturesjsx
*/
jsx?: boolean;
/**
* Controls whether the `loc` information to each node.
* The `loc` property is an object which contains the exact line/column the node starts/ends on.
* This is similar to the `range` property, except it is line/column relative.
*/
loc?: boolean;
/*
* Allows overriding of function used for logging.
* When value is `false`, no logging will occur.
* When value is not provided, `console.log()` will be used.
*/
loggerFn?: Function | false;
/**
* Controls whether the `range` property is included on AST nodes.
* The `range` property is a [number, number] which indicates the start/end index of the node in the file contents.
* This is similar to the `loc` property, except this is the absolute index.
*/
range?: boolean;
/**
* Set to true to create a top-level array containing all tokens from the file.
*/
tokens?: boolean;
}
const PARSE_DEFAULT_OPTIONS: ParseOptions = {
comment: false,
filePath: 'estree.ts', // or 'estree.tsx', if you pass jsx: true
jsDocParsingMode: 'all',
jsx: false,
loc: false,
loggerFn: undefined,
range: false,
tokens: false,
};
declare function parse(
code: string,
options: ParseOptions = PARSE_DEFAULT_OPTIONS,
): TSESTree.Program;
```
Example usage:
```js
import { parse } from '@typescript-eslint/typescript-estree';
const code = `const hello: string = 'world';`;
const ast = parse(code, {
loc: true,
range: true,
});
```
#### `parseAndGenerateServices(code, options)`
Parses the given string of code with the options provided and returns an ESTree-compatible AST. Accepts additional options which can be used to generate type information along with the AST.
```ts
interface ParseAndGenerateServicesOptions extends ParseOptions {
/**
* Granular control of the expiry lifetime of our internal caches.
* You can specify the number of seconds as an integer number, or the string
* 'Infinity' if you never want the cache to expire.
*
* By default cache entries will be evicted after 30 seconds, or will persist
* indefinitely if `disallowAutomaticSingleRunInference = false` AND the parser
* infers that it is a single run.
*/
cacheLifetime?: {
/**
* Glob resolution for `parserOptions.project` values.
*/
glob?: number | 'Infinity';
};
/**
* ESLint (and therefore typescript-eslint) is used in both "single run"/one-time contexts,
* such as an ESLint CLI invocation, and long-running sessions (such as continuous feedback
* on a file in an IDE).
*
* When typescript-eslint handles TypeScript Program management behind the scenes, this distinction
* is important because there is significant overhead to managing the so called Watch Programs
* needed for the long-running use-case.
*
* By default, we will use common heuristics to infer whether ESLint is being
* used as part of a single run. This option disables those heuristics, and
* therefore the performance optimizations gained by them.
*
* In other words, typescript-eslint is faster by default, and this option
* disables an automatic performance optimization.
*
* This setting's default value can be specified by setting a `TSESTREE_SINGLE_RUN`
* environment variable to `"false"` or `"true"`.
* Otherwise, the default value is `false`.
*/
disallowAutomaticSingleRunInference?: boolean;
/**
* Causes the parser to error if the TypeScript compiler returns any unexpected syntax/semantic errors.
*/
errorOnTypeScriptSyntacticAndSemanticIssues?: boolean;
/**
* When `project` is provided, this controls the non-standard file extensions which will be parsed.
* It accepts an array of file extensions, each preceded by a `.`.
*
* NOTE: When used with {@link projectService}, full project reloads may occur.
*/
extraFileExtensions?: string[];
/**
* Absolute (or relative to `tsconfigRootDir`) path to the file being parsed.
* When `project` is provided, this is required, as it is used to fetch the file from the TypeScript compiler's cache.
*/
filePath?: string;
/**
* Allows the user to control whether or not two-way AST node maps are preserved
* during the AST conversion process.
*
* By default: the AST node maps are NOT preserved, unless `project` has been specified,
* in which case the maps are made available on the returned `parserServices`.
*
* NOTE: If `preserveNodeMaps` is explicitly set by the user, it will be respected,
* regardless of whether or not `project` is in use.
*/
preserveNodeMaps?: boolean;
/**
* Absolute (or relative to `tsconfigRootDir`) paths to the tsconfig(s),
* or `true` to find the nearest tsconfig.json to the file.
* If this is provided, type information will be returned.
*
* If set to `false`, `null`, or `undefined`, type information will not be returned.
*
* Note that {@link projectService} is now preferred.
*/
project?: string[] | string | boolean | null;
/**
* If you provide a glob (or globs) to the project option, you can use this option to ignore certain folders from
* being matched by the globs.
* This accepts an array of globs to ignore.
*
* By default, this is set to ["/node_modules/"]
*/
projectFolderIgnoreList?: string[];
/**
* Whether to create a shared TypeScript project service to power program creation.
*/
projectService?: boolean | ProjectServiceOptions;
/**
* The absolute path to the root directory for all provided `project`s.
*/
tsconfigRootDir?: string;
/**
* An array of one or more instances of TypeScript Program objects to be used for type information.
* This overrides any program or programs that would have been computed from the `project` option.
* All linted files must be part of the provided program(s).
*/
programs?: Program[];
}
/**
* Granular options to configure the project service.
*/
interface ProjectServiceOptions {
/**
* Globs of files to allow running with the default project compiler options.
*/
allowDefaultProject?: string[];
/**
* Path to a TSConfig to use instead of TypeScript's default project configuration.
* @default 'tsconfig.json'
*/
defaultProject?: string;
/**
* Whether to load TypeScript plugins as configured in the TSConfig.
*/
loadTypeScriptPlugins?: boolean;
/**
* The maximum number of files {@link allowDefaultProject} may match.
* Each file match slows down linting, so if you do need to use this, please
* file an informative issue on typescript-eslint explaining why - so we can
* help you avoid using it!
* @default 8
*/
maximumDefaultProjectFileMatchCount_THIS_WILL_SLOW_DOWN_LINTING?: number;
}
interface ParserServices {
program: ts.Program;
esTreeNodeToTSNodeMap: WeakMap;
tsNodeToESTreeNodeMap: WeakMap;
}
interface ParseAndGenerateServicesResult {
ast: TSESTree.Program;
services: ParserServices;
}
const PARSE_AND_GENERATE_SERVICES_DEFAULT_OPTIONS: ParseOptions = {
...PARSE_DEFAULT_OPTIONS,
errorOnTypeScriptSyntacticAndSemanticIssues: false,
extraFileExtensions: [],
preserveNodeMaps: false, // or true, if you do not set this, but pass `project`
project: undefined,
projectFolderIgnoreList: ['/node_modules/'],
tsconfigRootDir: process.cwd(),
};
declare function parseAndGenerateServices(
code: string,
options: ParseOptions = PARSE_DEFAULT_OPTIONS,
): ParseAndGenerateServicesResult;
```
Example usage:
```js
import { parseAndGenerateServices } from '@typescript-eslint/typescript-estree';
const code = `const hello: string = 'world';`;
const { ast, services } = parseAndGenerateServices(code, {
filePath: '/some/path/to/file/foo.ts',
loc: true,
project: './tsconfig.json',
range: true,
});
```
### `TSESTree`, `AST_NODE_TYPES` and `AST_TOKEN_TYPES`
Types for the AST produced by the parse functions.
- `TSESTree` is a namespace which contains object types representing all of the AST Nodes produced by the parser.
- `AST_NODE_TYPES` is an enum which provides the values for every single AST node's `type` property.
- `AST_TOKEN_TYPES` is an enum which provides the values for every single AST token's `type` property.
### Utilities
#### `createProgram(configFile, projectDirectory)`
This serves as a utility method for users of the `ParseOptions.programs` feature to create a TypeScript program instance from a config file.
```ts
declare function createProgram(
configFile: string,
projectDirectory: string = process.cwd(),
): import('typescript').Program;
```
Example usage:
```js
const tsESTree = require('@typescript-eslint/typescript-estree');
const program = tsESTree.createProgram('tsconfig.json');
const code = `const hello: string = 'world';`;
const { ast, services } = parseAndGenerateServices(code, {
filePath: '/some/path/to/file/foo.ts',
loc: true,
program,
range: true,
});
```
## Debugging
If you encounter a bug with the parser that you want to investigate, you can turn on the debug logging via setting the environment variable: `DEBUG=typescript-eslint:*`.
I.e. in this repo you can run: `DEBUG=typescript-eslint:* yarn lint`.
This will include TypeScript server logs.
To turn off these logs, include `-typescript-eslint:typescript-estree:tsserver:*` when setting the environment variable.
I.e. for this repo change to: `DEBUG='typescript-eslint:*,-typescript-eslint:typescript-estree:tsserver:*' yarn lint`.
---
# TypeScript ESLint Documentation
# Source: https://raw.githubusercontent.com/typescript-eslint/typescript-eslint/main/docs/packages/Type_Utils.mdx
# Path: docs/packages/Type_Utils.mdx
---
id: type-utils
sidebar_label: type-utils
toc_max_heading_level: 3
---
import GeneratedDocs from './type-utils/generated/index.md';
# `@typescript-eslint/type-utils`
> Type utilities for working with TypeScript types ✨
This package contains public utilities for working with TypeScript types.
Rules declared in [`@typescript-eslint/eslint-plugin`](./ESLint_Plugin.mdx) use these utility functions.
The utilities in this package are both:
- More generally ESLint-focused than the broad TypeScript utilities in [`ts-api-utils`](https://npmjs.com/package/ts-api-utils)
- Separated from [`@typescript-eslint/utils`](./Utils.mdx) so that that package does not require a dependency on `typescript`
:::tip
See [Custom Rules](../developers/Custom_Rules.mdx) for documentation on creating your own custom ESLint rules for TypeScript code.
:::
---
The following documentation is auto-generated from source code.
---
# TypeScript ESLint Documentation
# Source: https://raw.githubusercontent.com/typescript-eslint/typescript-eslint/main/docs/packages/Utils.mdx
# Path: docs/packages/Utils.mdx
---
id: utils
sidebar_label: utils
toc_max_heading_level: 3
---
# `@typescript-eslint/utils`
> Utilities for working with TypeScript + ESLint together. ✨
This package contains public utilities for writing custom rules and plugins in TypeScript.
Rules declared in [`@typescript-eslint/eslint-plugin`](./ESLint_Plugin.mdx) are created using these utility functions.
Any custom rules you write generally will be as well.
> See [Custom Rules](../developers/Custom_Rules.mdx) for documentation on creating your own custom ESLint rules for TypeScript code.
## Exports
| Name | Description |
| ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `AST_NODE_TYPES` | An enum with the names of every single _node_ found in `TSESTree`. |
| `AST_TOKEN_TYPES` | An enum with the names of every single _token_ found in `TSESTree`. |
| `ASTUtils` | Tools for operating on the ESTree AST. Also includes the [`@eslint-community/eslint-utils`](https://www.npmjs.com/package/@eslint-community/eslint-utils) package, correctly typed to work with the types found in `TSESTree` |
| `ESLintUtils` | Tools for creating ESLint rules with TypeScript. |
| `JSONSchema` | Strict types for the JSON Schema v4 spec - the version that ESLint uses to validate all rules with. |
| `ParserServices` | Typing for the parser services provided when parsing a file using `@typescript-eslint/typescript-estree`. |
| `TSESLint` | Types for ESLint, correctly typed to work with the types found in `TSESTree`. |
| `TSESLintScope` | The [`eslint-scope`](https://www.npmjs.com/package/eslint-scope) package, correctly typed to work with the types found in both `TSESTree` and `TSESLint` |
| `TSESTree` | Types for the TypeScript flavor of ESTree created by `@typescript-eslint/typescript-estree`. |
---
# TypeScript ESLint Documentation
# Source: https://raw.githubusercontent.com/typescript-eslint/typescript-eslint/main/docs/packages/type-utils/TypeOrValueSpecifier.mdx
# Path: docs/packages/type-utils/TypeOrValueSpecifier.mdx
---
id: type-or-value-specifier
title: TypeOrValueSpecifier
---
Some lint rules include options to describe specific _types_ and/or _values_.
These options use a standardized format exported from the `type-utils` package, **`TypeOrValueSpecifier`**.
`TypeOrValueSpecifier` allows three object forms of specifiers:
- [`FileSpecifier`](#filespecifier): for types or values declared in local files
- [`LibSpecifier`](#libspecifier): for types or values declared in TypeScript's built-in lib definitions
- [`PackageSpecifier`](#packagespecifier): for types or values imported from packages
For example, the following configuration of [`@typescript-eslint/no-floating-promises` > `allowForKnownSafeCalls`](/rules/no-floating-promises#allowforknownsafecalls) marks `node:test`'s `it` as safe using a package specifier:
```json
{
"@typescript-eslint/no-floating-promises": [
"error",
{
"allowForKnownSafeCalls": [
{ "from": "package", "name": "it", "package": "node:test" }
]
}
]
}
```
Each object format requires at least:
- `from`: which specifier to use, as `'file' | 'lib' | 'package'`
- `name`: a `string` or `string[]` for type or value name(s) to match on
## FileSpecifier
```ts
interface FileSpecifier {
from: 'file';
name: string[] | string;
path?: string;
}
```
Describes specific types or values declared in local files.
`path` may be used to specify a file the types or values must be declared in.
If omitted, all files will be matched.
### FileSpecifier Examples
Matching all types and values named `Props`:
```json
{ "from": "file", "name": "Props" }
```
Matching all types and values named `Props` in `file.tsx`:
```json
{ "from": "file", "name": "Props", "path": "file.tsx" }
```
## LibSpecifier
```ts
interface LibSpecifier {
from: 'lib';
name: string[] | string;
}
```
Describes specific types or values declared in TypeScript's built-in `lib.*.d.ts` ("lib") types.
Lib types include `lib.dom.d.ts` globals such as `Window` and `lib.es*.ts` globals such as `Array`.
### LibSpecifier Examples
Matching all strings:
```json
{ "from": "lib", "name": "string" }
```
Matching all array-typed values:
```json
{ "from": "lib", "name": "Array" }
```
Matching all `Promise` and `PromiseLike`-typed values:
```json
{ "from": "lib", "name": ["Promise", "PromiseLike"] }
```
## PackageSpecifier
```ts
interface PackageSpecifier {
from: 'package';
name: string[] | string;
package: string;
}
```
Describes specific types or values imported from packages.
`package` must be used to specify the package name.
### PackageSpecifier Examples
Matching the `SafePromise` type from `@reduxjs/toolkit`:
```json
{ "from": "package", "name": "SafePromise", "package": "@reduxjs/toolkit" }
```
Matching the `describe`, `it`, and `test` values from `vitest`:
```json
{ "from": "package", "name": ["describe", "it", "test"], "package": "vitest" }
```
## Universal String Specifiers
`TypeOrValueSpecifier` also allows providing a plain string specifier to match all names regardless of declaration source.
For example, providing `"RegExp"` matches _all_ types and values named `RegExp`.
:::danger
We strongly recommend not using universal string specifiers.
Matching _all_ names without specifying a source file, library, or package can accidentally match other types or values with a coincidentally similar name.
Universal string specifiers will be removed in a future major version of typescript-eslint.
:::
## Rule Options Using This Format
- [`@typescript-eslint/no-floating-promises` > `allowForKnownSafeCalls`](/rules/no-floating-promises#allowforknownsafecalls)
- [`@typescript-eslint/no-floating-promises` > `allowForKnownSafePromises`](/rules/no-floating-promises#allowforknownsafepromises)
- [`@typescript-eslint/only-throw-error` > `allow`](/rules/only-throw-error/#allow)
- [`@typescript-eslint/prefer-readonly-parameter-types` > `allow`](/rules/prefer-readonly-parameter-types/#allow)
---
# TypeScript ESLint Documentation
# Source: https://raw.githubusercontent.com/typescript-eslint/typescript-eslint/main/docs/packages/typescript-estree/AST_Spec.mdx
# Path: docs/packages/typescript-estree/AST_Spec.mdx
---
id: ast-spec
sidebar_label: AST Specification
toc_max_heading_level: 3
---
import GeneratedDocs from '../ast-spec/generated/index.md';
# AST Specification
The following auto-generated documentation describes the Abstract Syntax Tree (AST) generated by [`@typescript-eslint/typescript-estree`](../TypeScript_ESTree.mdx) for parsers such as [`@typescript-eslint/parser`](../Parser.mdx).
---
# TypeScript ESLint Documentation
# Source: https://raw.githubusercontent.com/typescript-eslint/typescript-eslint/main/docs/troubleshooting/faqs/ESLint.mdx
# Path: docs/troubleshooting/faqs/ESLint.mdx
---
id: eslint
sidebar_label: ESLint
title: ESLint FAQs
---
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
## Why is a rule from ESLint core not working correctly with TypeScript code?
This happens because TypeScript adds new features that ESLint doesn't know about.
The first step is to [check our list of "extension" rules here](/rules/#extension-rules).
An extension rule is a rule which extends the base ESLint rules to support TypeScript syntax.
If you find it in there, give it a go to see if it works for you.
You can configure it by disabling the base rule, and turning on the extension rule.
Here's an example with the `semi` rule:
```json
{
"rules": {
"semi": "off",
"@typescript-eslint/semi": "error"
}
}
```
If you don't find an existing extension rule, or the extension rule doesn't work for your case, then you can go ahead and check our issues.
[The contributing guide outlines the best way to raise an issue](../../contributing/Issues.mdx).
> We release a new version our tooling every week.
> _Please_ ensure that you [check our the latest list of "extension" rules](/rules/#extension-rules) **_before_** filing an issue.
## I get errors from the `no-undef` rule about global variables not being defined, even though there are no TypeScript errors
The `no-undef` lint rule does not use TypeScript to determine the global variables that exist - instead, it relies upon ESLint's configuration.
We strongly recommend that you do not use the `no-undef` lint rule on TypeScript projects.
The checks it provides are already provided by TypeScript without the need for configuration - TypeScript just does this significantly better.
As of our v4.0.0 release, this also applies to types.
If you use global types from a 3rd party package (i.e. anything from an `@types` package), then you will have to configure ESLint appropriately to define these global types.
For example; the `JSX` namespace from `@types/react` is a global 3rd party type that you must define in your ESLint config.
Note, that for a mixed project including JavaScript and TypeScript, the `no-undef` rule (like any rule) can be turned off for TypeScript files alone as follows:
```js title="eslint.config.mjs"
import { defineConfig } from 'eslint/config';
export default defineConfig(
// ... the rest of your config ...
{
files: ['**/*.{ts,tsx,mts,cts}'],
rules: {
'no-undef': 'off',
},
},
);
```
```js title=".eslintrc.js"
module.exports = {
// ... the rest of your config ...
overrides: [
{
files: ['*.ts', '*.mts', '*.cts', '*.tsx'],
rules: {
'no-undef': 'off',
},
},
],
};
```
If you choose to leave on the ESLint `no-undef` lint rule, you can [manually define the set of allowed `globals` in your ESLint config](https://eslint.org/docs/user-guide/configuring/language-options#specifying-globals), and/or you can use one of the [pre-defined environment (`env`) configurations](https://eslint.org/docs/user-guide/configuring/language-options#specifying-environments).
## I get errors from the `@typescript-eslint/no-namespace` and/or `no-var` rules about declaring global variables
Two common solutions in TypeScript for declaring the existence of a global variable include:
- `declare global` with a `var`, which violates [`no-var`](https://eslint.org/docs/latest/rules/no-var):
```ts
declare global {
var myValue: string;
// Unexpected var, use let or const instead. eslint (no-var)
}
myValue;
```
- `declare namespace globalThis`, which violates [`@typescript-eslint/no-namespace`](https://typescript-eslint.io/rules/no-namespace):
```ts
declare namespace globalThis {
// ES2015 module syntax is preferred over namespaces. eslint (@typescript-eslint/no-namespace)
let myValue: string;
}
globalThis.myValue;
```
[Using global variables is generally discouraged](https://stackoverflow.com/questions/10525582/why-are-global-variables-considered-bad-practice).
If possible, it's best to avoid declaring globals altogether.
If you absolutely must use one of the two strategies, then you can use an [ESLint configuration comment](https://eslint.org/docs/latest/use/configure/rules#using-configuration-comments-1) to disable rules as needed.
For example:
```ts
declare global {
// eslint-disable-next-line no-var -- Provided by an old third-party integration.
var myValue: string;
}
```
:::tip
Whenever you need to disable an ESLint rule, it's best to include an informative comment explaining why.
:::
See [#9582](https://github.com/typescript-eslint/typescript-eslint/issues/9582 'typescript-eslint/typescript-eslint#9582 Docs: globalThis without ignores of no-var and no-namespace') and [#7941](https://github.com/typescript-eslint/typescript-eslint/issues/7941 'typescript-eslint/typescript-eslint#7941 Base rule extension: no-var configuration for declarations') for discussions around typescript-eslint supporting these use cases.
## Can I use ESLint's `--cache` with typescript-eslint?
[ESLint's `--cache` option](https://eslint.org/docs/latest/use/command-line-interface#caching) caches on a per-file basis.
You can use it, but it will only work reliably for untyped rules -- and even then, not always.
Any ESLint rule that checks logic across files, including many rules from `eslint-plugin-import`, creates cross-file dependencies.
[Typed lint rules](../../getting-started/Typed_Linting.mdx) almost always have dependencies on types across files in practice.
ESLint's caching doesn't account for those cross-file dependencies.
We don't recommend using `--cache`.
---
# TypeScript ESLint Documentation
# Source: https://raw.githubusercontent.com/typescript-eslint/typescript-eslint/main/docs/troubleshooting/faqs/Frameworks.mdx
# Path: docs/troubleshooting/faqs/Frameworks.mdx
---
id: frameworks
sidebar_label: Frameworks
title: Framework FAQs
---
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
## I use a framework (like Vue) that requires custom file extensions, and I get errors like "You should add `parserOptions.extraFileExtensions` to your config"
You can use `parserOptions.extraFileExtensions` to specify an array of non-TypeScript extensions to allow, for example:
:::note
See [Changes to `extraFileExtensions` with `projectService`](../typed-linting/Performance.mdx#changes-to-extrafileextensions-with-projectservice) to avoid performance issues.
:::
```js title="eslint.config.mjs"
export default defineConfig(
// ... the rest of your config ...
{
languageOptions: {
parserOptions: {
// Add this line
extraFileExtensions: ['.vue'],
projectService: true,
},
},
},
);
```
```js title=".eslintrc.js"
module.exports = {
// ... the rest of your config ...
parserOptions: {
// Add this line
extraFileExtensions: ['.vue'],
projectService: true,
tsconfigRootDir: __dirname,
},
};
```
## I am running into errors when parsing TypeScript in my .vue files
If you are running into issues parsing .vue files, it might be because parsers like [`vue-eslint-parser`](https://www.npmjs.com/package/vue-eslint-parser) are required to parse `.vue` files. In this case you can move `@typescript-eslint/parser` inside `parserOptions` and use `vue-eslint-parser` as the top level parser.
```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 defineConfig(
// ... the rest of your config ...
{
languageOptions: {
// Remove this line
parser: tseslint.parser,
// Add this line
parser: vueParser,
parserOptions: {
// Add this line
parser: tseslint.parser,
sourceType: 'module',
},
},
},
);
```
```js title=".eslintrc.js"
module.exports = {
// ... the rest of your config ...
// Remove this line
parser: '@typescript-eslint/parser',
// Add this line
parser: 'vue-eslint-parser',
parserOptions: {
parser: '@typescript-eslint/parser',
// Add this line
extraFileExtensions: ['.vue'],
},
};
```
The `parserOptions.parser` option can also specify an object to specify multiple parsers. See the [`vue-eslint-parser` usage guide](https://eslint.vuejs.org/user-guide/#usage) for more details.
---
# TypeScript ESLint Documentation
# Source: https://raw.githubusercontent.com/typescript-eslint/typescript-eslint/main/docs/troubleshooting/faqs/General.mdx
# Path: docs/troubleshooting/faqs/General.mdx
---
id: general
title: General
pagination_next: troubleshooting/faqs/eslint
---
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
## How do I turn on a `@typescript-eslint` rule?
First make sure you've read the docs and understand ESLint configuration files:
- [Read our getting started guide](../../getting-started/Quickstart.mdx) to ensure your config is properly setup to start configuring our rules.
- [Checkout ESLint's documentation on configuring rules](https://eslint.org/docs/latest/use/configure/rules) to ensure you understand how to configure rules.
Our [rule docs](/rules) detail the options each rule supports under the "Options" heading.
We use TypeScript types to describe an `Options` tuple type for the rule which you can use to configure the rule.
In your config file the keys of the `rules` object are the names of the rules you wish to configure and the values follow the following form:
```ts
type Severity = 'off' | 'warn' | 'error';
type RuleConfig =
| Severity
| [Severity]
| [
Severity,
// Options is the tuple type from the rule docs
...Options,
];
```
Some examples
```js title="eslint.config.mjs"
export default defineConfig(
// ... the rest of your config ...
{
rules: {
// turns a rule on with no configuration (i.e. uses the default configuration)
'@typescript-eslint/array-type': 'error',
// turns on a rule with configuration
'@typescript-eslint/no-explicit-any': ['warn', { ignoreRestArgs: true }],
},
},
);
```
```js title=".eslintrc.cjs"
module.exports = {
// ... the rest of your config ...
rules: {
// turns a rule on with no configuration (i.e. uses the default configuration)
'@typescript-eslint/array-type': 'error',
// turns on a rule with configuration
'@typescript-eslint/no-explicit-any': ['warn', { ignoreRestArgs: true }],
},
};
```
## How can I ban ``?
ESLint core contains the rule [`no-restricted-syntax`](https://eslint.org/docs/rules/no-restricted-syntax).
This generic rule allows you to specify a [selector](https://eslint.org/docs/developer-guide/selectors) for the code you want to ban, along with a custom error message.
You can use an AST visualization tool such as [typescript-eslint playground](/play#showAST=es) > _Options_ > _AST Explorer_ on its left sidebar by selecting _ESTree_ to help in figuring out the structure of the AST that you want to ban.
Banning confusing property uses
```jsonc
{
"rules": {
"no-restricted-syntax": [
"error",
// Ban accessing `constructor.name`:
{
"selector": "MemberExpression[object.property.name='constructor'][property.name='name']",
"message": "'constructor.name' is not reliable after code minifier usage.",
},
// Ban get and set accessors:
{
"selector": "Property:matches([kind = \"get\"], [kind = \"set\"]), MethodDefinition:matches([kind = \"get\"], [kind = \"set\"])",
"message": "Don't use get and set accessors.",
},
],
},
}
```
Banning specific uses of class properties
```jsonc
{
"rules": {
"no-restricted-syntax": [
"error",
// Ban `private` members:
{
"selector": ":matches(PropertyDefinition, MethodDefinition)[accessibility=\"private\"]",
"message": "Use `#private` members instead.",
},
// Ban `#private` members:
{
"selector": ":matches(PropertyDefinition, MethodDefinition) > PrivateIdentifier.key",
"message": "Use the `private` modifier instead.",
},
// Ban static `this`:
{
"selector": "MethodDefinition[static = true] ThisExpression",
"message": "Prefer using the class's name directly.",
},
],
},
}
```
Banning specific uses of TypeScript enums
```jsonc
{
"rules": {
"no-restricted-syntax": [
"error",
// Ban all enums:
{
"selector": "TSEnumDeclaration",
"message": "My reason for not using any enums at all.",
},
// Ban just `const` enums:
{
"selector": "TSEnumDeclaration[const=true]",
"message": "My reason for not using const enums.",
},
// Ban just non-`const` enums:
{
"selector": "TSEnumDeclaration:not([const=true])",
"message": "My reason for not using non-const enums.",
},
],
},
}
```
Banning specific uses of TypeScript tuples
```jsonc
{
"rules": {
"no-restricted-syntax": [
"error",
// enforce tuple members have labels
{
"selector": "TSTupleType > :not(TSNamedTupleMember)",
"message": "All tuples should have labels.",
},
],
},
}
```
## How do I check to see what versions are installed?
If you have multiple versions of our tooling, it can cause various bugs for you.
This is because ESLint may load a different version each run depending on how you run it - leading to inconsistent lint results.
Installing our tooling in the root of your project does not mean that only one version is installed.
One or more of your dependencies may have its own dependency on our tooling, meaning `npm`/`yarn` will additionally install that version for use by that package.
For example, `react-scripts` (part of `create-react-app`) has a dependency on our tooling.
You can check what versions are installed in your project using the following commands:
```bash npm2yarn
npm list @typescript-eslint/eslint-plugin @typescript-eslint/parser
```
If you see more than one version installed, then you will have to either use [yarn resolutions](https://classic.yarnpkg.com/en/docs/selective-version-resolutions) to force a single version, or you will have to downgrade your root versions to match the dependency versions.
**The best course of action in this case is to wait until your dependency releases a new version with support for our latest versions.**
## Changes to one file are not reflected when linting other files in my IDE
> tl;dr: Restart your ESLint server to force an update.
ESLint currently does not have any way of telling parsers such as ours when an arbitrary file is changed on disk.
That means if you change file A that is imported by file B, it won't update lint caches for file B -- even if file B's text contents have changed.
Sometimes the only solution is to restart your ESLint editor extension altogether.
See [this issue comment](https://github.com/typescript-eslint/typescript-eslint/issues/5845#issuecomment-1283248238 'GitHub issue 5845, comment 1283248238: details on ESLint cross-file caching') for more information.
:::tip
[VS Code's ESLint extension](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint) provides an `ESLint: Restart ESLint Server` action.
:::
### I get `no-unsafe-*` complaints for cross-file changes
See [Changes to one file are not reflected in linting other files in my IDE](#changes-to-one-file-are-not-reflected-when-linting-other-files-in-my-ide).
Rules such as [`no-unsafe-argument`](/rules/no-unsafe-argument), [`no-unsafe-assignment`](/rules/no-unsafe-assignment), and [`no-unsafe-call`](/rules/no-unsafe-call) are often impacted.
## How does typescript-eslint compare to native-speed linters?
"Native-speed" linters such as [Biome linter](https://biomejs.dev/linter), [Deno linter](https://docs.deno.com/runtime/manual/tools/linter), and [oxlint](https://oxc.rs/docs/guide/usage/linter.html) run in very fast languages such as Go or Rust, and so can generally run significantly faster than ESLint in non-type-aware-linting.
They can also be easier to configure because they don't need to support the full ecosystem and legacy trail of ESLint.
However, until they support [typed linting](../../getting-started/Typed_Linting.mdx), they aren't a full replacement for typescript-eslint.
If you plan on using them, we recommend "dual linting": using those linters for what they support, then adding in ESLint for typed linting in a parallel or second step.
Our `*-type-checked-only` [Shared Configs](../../users/Shared_Configurations.mdx) will enable only type-checked rules in your ESLint config.
For example, the following config enables only the recommended config's type-checked rules with [`recommendedTypeCheckedOnly`](../../users/Shared_Configurations.mdx#recommended-type-checked-only):
{/* prettier-ignore */}
```js title="eslint.config.mjs"
import eslint from '@eslint/js';
import { defineConfig } from 'eslint/config';
import tseslint from 'typescript-eslint';
export default defineConfig(
tseslint.configs.recommendedTypeCheckedOnly,
{
languageOptions: {
parserOptions: {
projectService: true,
},
},
},
);
```
```js title=".eslintrc.cjs"
module.exports = {
extends: ['plugin:@typescript-eslint/recommended-type-checked-only'],
parserOptions: {
projectService: true,
tsconfigRootDir: __dirname,
},
root: true,
};
```
For example, [oxlint's Integration > ESLint documentation](https://oxc.rs/docs/guide/usage/linter#eslint) describes how to turn off ESLint rules that are already supported by oxlint.
## "The '``' property is deprecated on '``' nodes. Use '``' instead." warnings
If you're seeing this warning, it's likely you're using an ESLint plugin (or other tooling) that hasn't been updated for typescript-eslint v6.
Make sure you're using the latest versions of each of your ESLint plugins (and other tooling).
If you're using many ESLint plugins, have updated each to their latest version, and you're not sure which one this complaint is coming from, try either or both of:
- Running with [`--trace-deprecation`](https://nodejs.org/api/cli.html#--trace-deprecation) (e.g. `npx cross-env NODE_OPTIONS=--trace-deprecation npm run lint`)
- Disabling half of them at a time to narrow down which plugin it is
Then make sure each of those plugins has a GitHub issue asking that they release a version supporting typescript-eslint v6.
:::tip
For developers updating ESLint rules in plugins that still need to support typescript-eslint v5: you may need to `||` fall back to the old property key if the new one doesn't exist:
```diff
- node.typeParameters
+ node.typeArguments || node.typeParameters
```
:::
For more context, see the [Some properties named typeParameters instead of typeArguments](https://github.com/typescript-eslint/typescript-eslint/issues/146) issue, and the implementing [fix: rename typeParameters to typeArguments where needed](https://github.com/typescript-eslint/typescript-eslint/pull/5384) pull request.
The [typescript-eslint v6 release post](/blog/announcing-typescript-eslint-v6-beta) has more information on typescript-eslint v6.
## My linting feels really slow
If you think you're having issues with performance, see our [Performance Troubleshooting documentation](../../troubleshooting/typed-linting/Performance.mdx).
---
# TypeScript ESLint Documentation
# Source: https://raw.githubusercontent.com/typescript-eslint/typescript-eslint/main/docs/troubleshooting/faqs/JavaScript.mdx
# Path: docs/troubleshooting/faqs/JavaScript.mdx
---
id: javascript
sidebar_label: JavaScript
title: JavaScript FAQs
---
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
## One of my lint rules isn't working correctly on a pure JavaScript file
This is to be expected - ESLint rules do not check file extensions on purpose, as it causes issues in environments that use non-standard extensions (for example, a `.vue` and a `.md` file can both contain TypeScript code to be linted).
If you have some pure JavaScript code that you do not want to apply certain lint rules to, then you can use [ESLint's `files` configuration](https://eslint.org/docs/latest/use/configure/configuration-files#specifying-files-and-ignores) to either:
- (recommended) only enable TypeScript-specific rules on TypeScript file extensions
- turn off TypeScript-specific rules on JavaScript-only file extensions
## Should I run ESLint on transpiled output JavaScript files?
No.
Source TypeScript files have all the content of output JavaScript files, plus type annotations.
There's no benefit to also linting output JavaScript files.
---
# TypeScript ESLint Documentation
# Source: https://raw.githubusercontent.com/typescript-eslint/typescript-eslint/main/docs/troubleshooting/faqs/TypeScript.mdx
# Path: docs/troubleshooting/faqs/TypeScript.mdx
---
id: typescript
sidebar_label: TypeScript
title: TypeScript FAQs
---
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
## Should TypeScript be installed globally or locally?
Make sure that you have installed TypeScript locally i.e. by using `npm install typescript`, not `npm install -g typescript`,
or by using `yarn add typescript`, not `yarn global add typescript`.
See [#2041](https://github.com/typescript-eslint/typescript-eslint/issues/2041) for more information.
## Why don't I see TypeScript errors in my ESLint output?
TypeScript's compiler (or whatever your build chain may be) is specifically designed and built to validate the correctness of your codebase.
Our tooling does not reproduce the errors that TypeScript provides, because doing so would slow down the lint run [1], and duplicate the errors that TypeScript already outputs for you.
Instead, our tooling exists to **_augment_** TypeScript's built in checks with lint rules that consume the type information in new ways beyond just verifying the runtime correctness of your code.
[1] - TypeScript computes type information lazily, so us asking for the errors it would produce from the compiler would take an _additional_ ~100ms per file.
This doesn't sound like a lot, but depending on the size of your codebase, it can easily add up to between several seconds to several minutes to a lint run.
## How can I specify a TypeScript version / `parserOptions.typescriptLocation`?
You can't, and you don't want to.
You should use the same version of TypeScript for linting as the rest of your project.
TypeScript versions often have slight differences in edge cases that can cause contradictory information between typescript-eslint rules and editor information.
For example:
- `@typescript-eslint/strict-boolean-expressions` might be operating with TypeScript version _X_ and think a variable is `string[] | undefined`
- TypeScript itself might be on version _X+1-beta_ and think the variable is `string[]`
See [this issue comment](https://github.com/typescript-eslint/typescript-eslint/issues/4102#issuecomment-963265514) for more details.
## Why aren't `// @ts-expect-error` or `// @ts-ignore` comments affecting lint results?
[`// @ts-expect-error`](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-9.html#-ts-expect-error-comments) and [`// @ts-ignore`](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-6.html#suppress-errors-in-ts-files-using--ts-ignore-comments) comment directives are a feature of TypeScript.
They only impact TypeScript's type checking.
TypeScript (a type checker) is a separate tool from ESLint (a linter).
Similar, [ESLint configuration comments](https://eslint.org/docs/latest/use/configure/rules#using-configuration-comments) like `/* eslint ... */` only impact ESLint.
They don't change anything with TypeScript's type checking.
:::tip
You can use ESLint to enforce good uses of both ESLint and TypeScript comment directives:
- The [`@typescript-eslint/ban-ts-comment`](/rules/ban-ts-comment) rule can disallow `@ts-...` comments and/or require comment descriptions to explain their use
- 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.
---
# TypeScript ESLint Documentation
# Source: https://raw.githubusercontent.com/typescript-eslint/typescript-eslint/main/docs/troubleshooting/typed-linting/Monorepos.mdx
# Path: docs/troubleshooting/typed-linting/Monorepos.mdx
---
id: monorepos
slug: /troubleshooting/typed-linting/monorepos
title: Monorepo Configuration
---
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
:::tip
**The [new "project service" in v8](/blog/announcing-typescript-eslint-v8-beta#project-service) requires no additional configuration for monorepos.**
If you're using `parserOptions.projectService`, you don't need this guide.
:::
If you're using a monorepo with `parserOptions.project`, these docs will help you figure out how to setup typed linting.
If you don't want to use typed linting, then you can stop here - you don't need to do anything special.
`parserOptions.project` configurations will look different based on which monorepo setup you use:
1. [One root `tsconfig.json`](#one-root-tsconfigjson)
2. [One `tsconfig.json` per package (and an optional one in the root)](#one-tsconfigjson-per-package-and-an-optional-one-in-the-root)
## One root `tsconfig.json`
If you only have one `tsconfig.json` file _and_ its `include` paths include all the files you'd like to lint, you can directly use it with typescript-eslint without further configuration.
If its `include` paths cannot include all files to be linted, we suggest creating a new config called `tsconfig.eslint.json`, that looks something like this:
```jsonc title="tsconfig.eslint.json"
{
// extend your base config to share compilerOptions, etc
"extends": "./tsconfig.json",
"compilerOptions": {
// ensure that nobody can accidentally use this config for a build
"noEmit": true,
},
"include": [
// whatever paths you intend to lint
"src",
"test",
"tools",
],
}
```
Be sure to update your ESLint configuration file to point at this new TSConfig.
## One `tsconfig.json` per package (and an optional one in the root)
The `parserOptions.project` option introduced in [Linting with Type Information](../typed-linting/index.mdx) accepts an array of relative paths.
Paths may be provided as [Node globs](https://github.com/isaacs/node-glob/blob/f5a57d3d6e19b324522a3fa5bdd5075fd1aa79d1/README.md#glob-primer).
For each file being linted, the first matching project path will be used as its backing TSConfig.
```js title="eslint.config.mjs"
export default defineConfig(
eslint.configs.recommended,
tseslint.configs.recommendedTypeChecked,
{
languageOptions: {
parserOptions: {
// Remove this line
project: true,
// Add this line
project: ['./tsconfig.eslint.json', './packages/*/tsconfig.json'],
},
},
},
);
```
```js title=".eslintrc.js"
/* eslint-env node */
module.exports = {
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended-type-checked',
],
parser: '@typescript-eslint/parser',
parserOptions: {
// Remove this line
project: true,
// Add this line
project: ['./tsconfig.eslint.json', './packages/*/tsconfig.json'],
},
plugins: ['@typescript-eslint'],
root: true,
};
```
### Wide globs in `parserOptions.project`
Using wide globs `**` in your `parserOptions.project` may degrade linting performance.
Instead of globs that use `**` to recursively check all folders, prefer paths that use a single `*` at a time.
```js title="eslint.config.mjs"
export default defineConfig(
eslint.configs.recommended,
tseslint.configs.recommendedTypeChecked,
{
languageOptions: {
parserOptions: {
// Remove this line
project: ['./tsconfig.eslint.json', './**/tsconfig.json'],
// Add this line
project: ['./tsconfig.eslint.json', './packages/*/tsconfig.json'],
},
},
},
);
```
```js title=".eslintrc.js"
/* eslint-env node */
module.exports = {
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
'plugin:@typescript-eslint/recommended-type-checked',
],
parser: '@typescript-eslint/parser',
parserOptions: {
// Remove this line
project: ['./tsconfig.eslint.json', './**/tsconfig.json'],
// Add this line
project: ['./tsconfig.eslint.json', './packages/*/tsconfig.json'],
tsconfigRootDir: __dirname,
},
plugins: ['@typescript-eslint'],
root: true,
};
```
See [Glob pattern in parser's option "project" slows down linting](https://github.com/typescript-eslint/typescript-eslint/issues/2611) for more details.
### Important note regarding large (> 10) multi-package monorepos
We've had reports that for sufficiently large and/or interdependent projects, you may run into OOMs using this approach.
Our advice is to set it up and test first, as there are very few cases that trigger this OOM.
See [#1192](https://github.com/typescript-eslint/typescript-eslint/issues/1192) for more information and discussion.
If you do run into an OOM, please comment on the above issue and let us know about your repo - the more information we have, the better.
As an interim workaround, consider one of the following:
- Switching to one root `tsconfig.eslint.json` (see [One root `tsconfig.json`](#one-root-tsconfigjson))
- Using a shell script to only lint one package at a time, using your existing config above.
---
# TypeScript ESLint Documentation
# Source: https://raw.githubusercontent.com/typescript-eslint/typescript-eslint/main/docs/troubleshooting/typed-linting/Performance.mdx
# Path: docs/troubleshooting/typed-linting/Performance.mdx
---
id: performance
slug: /troubleshooting/typed-linting/performance
title: Performance
---
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
As mentioned in [Linting with Type Information](../../getting-started/Typed_Linting.mdx), if you're using type-aware linting, your lint times should be roughly the same as your build times.
Most performance slowdowns in ESLint rules are from type-aware lint rules calling to TypeScript's type checking APIs.
If you're experiencing lint times much slower than type-checking times, then there are a few common culprits.
## Slow ESLint Rules
ESLint includes a `TIMING=1` option documented in [Profile Rule Performance](https://eslint.org/docs/latest/extend/custom-rules#profile-rule-performance) that give a high-level overview of rule speeds.
However, because TypeScript utilizes internal caching, a project's _first type-aware lint rule will almost always seem the slowest_.
When investigating which lint rules are the slowest in your project, be sure to run them one at a time and compare those timing measurements separately.
To enable more complete verbose logging, you can use any of:
- [`eslint --debug`](https://eslint.org/docs/latest/use/command-line-interface#--debug): to enable all of ESLint's debug logs on the CLI
- [`parserOptions.debugLevel`](https://github.com/typescript-eslint/typescript-eslint/blob/7ddadda10845bc53967eeec83ba6b7cdc71a079f/packages/typescript-estree/src/parser-options.ts#L36): a shortcut to set `eslint`, `typescript`, and/or `typescript-eslint`
- Directly setting the `DEBUG` environment variable for [`debug`](https://github.com/debug-js/debug): e.g. `DEBUG=typescript-eslint:* eslint`
## Slow TypeScript Types
Running typed linting on a project is generally as slow as type checking that same project.
If TypeScript's type checker runs slowly on your project, then typed linting will as well.
The [TypeScript Wiki's Performance page](https://github.com/microsoft/TypeScript/wiki/Performance) includes general performance tips and steps to investigate slow type checking.
In particular for typed linting:
- [Investigating Issues](https://github.com/microsoft/TypeScript/wiki/Performance#investigating-issues) can spot slow types and type checking:
- [Running `tsc` alone](https://github.com/microsoft/TypeScript/wiki/Performance#running-tsc-alone) should provide a baseline for your full project's type checking speed.
- [Performance Tracing](https://github.com/microsoft/TypeScript/wiki/Performance#performance-tracing) can spotlight specific slow types within your project.
- [Using Project References](https://github.com/microsoft/TypeScript/wiki/Performance#using-project-references) -which requires enabling the [new "project service" (`parserOptions.projectService`) in v8](/blog/announcing-typescript-eslint-v8-beta#project-service)- can be helpful to speed up type checking on larger projects.
If none of the above work, you can try adjusting the `--max-semi-space-size` of Node. Increasing the max size of a semi-space can improve performance at the cost of more memory consumption. You can [read more about setting space size in Node.js here](https://nodejs.org/api/cli.html#--max-semi-space-sizesize-in-mib).
You can enable the setting by prepending your ESLint command like:
```bash
NODE_OPTIONS=--max-semi-space-size=256 eslint
```
## Wide includes in your `tsconfig`
When using type-aware linting, you provide us with one or more tsconfigs.
We then will pre-parse all files so that full and complete type information is available.
If you provide very wide globs in your `include` (such as `**/*`), it can cause many more files than you expect to be included in this pre-parse.
Additionally, if you provide no `include` in your tsconfig, then it is the same as providing the widest glob.
Wide globs can cause TypeScript to parse things like build artifacts, which can heavily impact performance.
Always ensure you provide globs targeted at the folders you are specifically wanting to lint.
## Project Service Issues
### Changes to `extraFileExtensions` with `projectService`
Using a different [`extraFileExtensions`](../../packages/Parser.mdx#extrafileextensions) between files in the same project with
the [`projectService`](../../packages/Parser.mdx#projectservice) option may cause performance degradations.
For every file linted, we update the `projectService` whenever `extraFileExtensions` changes.
This causes the underlying TypeScript server to perform a full project reload.
```js title="eslint.config.js"
// @ts-check
import tseslint from 'typescript-eslint';
import vueParser from 'vue-eslint-parser';
// Add this line
const extraFileExtensions = ['.vue'];
export default [
{
files: ['*.ts'],
languageOptions: {
parser: tseslint.parser,
parserOptions: {
projectService: true,
// Add this line
extraFileExtensions,
},
},
},
{
files: ['*.vue'],
languageOptions: {
parser: vueParser,
parserOptions: {
projectService: true,
parser: tseslint.parser,
// Remove this line
extraFileExtensions: ['.vue'],
// Add this line
extraFileExtensions,
},
},
},
];
```
```js title=".eslintrc.js"
// Add this line
const extraFileExtensions = ['.vue'];
module.exports = {
files: ['*.ts'],
parser: '@typescript-eslint/parser',
parserOptions: {
projectService: true,
// Add this line
extraFileExtensions,
},
overrides: [
{
files: ['*.vue'],
parser: 'vue-eslint-parser',
parserOptions: {
parser: '@typescript-eslint/parser',
projectService: true,
// Remove this line
extraFileExtensions: ['.vue'],
// Add this line
extraFileExtensions,
},
},
],
};
```
Project reloads can be observed using the [debug environment variable](../../packages/typescript-estree/#debugging): `DEBUG='typescript-eslint:typescript-estree:*'`.
```
typescript-estree:useProgramFromProjectService Updating extra file extensions: before=[]: after=[ '.vue' ]
typescript-estree:tsserver:info reload projects.
typescript-estree:useProgramFromProjectService Extra file extensions updated: [ '.vue' ]
...
typescript-estree:useProgramFromProjectService Updating extra file extensions: before=[ '.vue' ]: after=[]
typescript-estree:tsserver:info reload projects.
typescript-estree:useProgramFromProjectService Extra file extensions updated: []
...
typescript-estree:tsserver:info Scheduled: /path/to/tsconfig.src.json, Cancelled earlier one +0ms
typescript-estree:tsserver:info Scheduled: *ensureProjectForOpenFiles*, Cancelled earlier one +0ms
...
typescript-estree:useProgramFromProjectService Updating extra file extensions: before=[]: after=[ '.vue' ]
typescript-estree:tsserver:info reload projects.
typescript-estree:useProgramFromProjectService Extra file extensions updated: [ '.vue' ]
```
## Traditional Project issues
### Wide includes in your ESLint options
:::tip
The [new "project service" in v8](/blog/announcing-typescript-eslint-v8-beta#project-service) requires no additional configuration for wide TSConfig includes.
If you're using `parserOptions.projectService`, this problem is solved for you.
:::
Specifying `tsconfig.json` paths in an ESLint `parserOptions.project` configuration is also likely to cause much more disk IO than expected.
Instead of globs that use `**` to recursively check all folders, prefer paths that use a single `*` at a time.
```js title="eslint.config.mjs"
// @ts-check
import eslint from '@eslint/js';
import tseslint from 'typescript-eslint';
export default defineConfig(
eslint.configs.recommended,
tseslint.configs.recommendedRequiringTypeChecking,
{
languageOptions: {
parserOptions: {
// Remove this line
project: ['./**/tsconfig.json'],
// Add this line
project: ['./packages/*/tsconfig.json'],
},
},
},
);
```
```js title=".eslintrc.js"
module.exports = {
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended-requiring-type-checking',
],
parser: '@typescript-eslint/parser',
parserOptions: {
tsconfigRootDir: __dirname,
// Remove this line
project: ['./**/tsconfig.json'],
// Add this line
project: ['./packages/*/tsconfig.json'],
},
plugins: ['@typescript-eslint'],
root: true,
};
```
See [Glob pattern in parser's option "project" slows down linting](https://github.com/typescript-eslint/typescript-eslint/issues/2611) for more details.
## Third-Party Plugins
### `@stylistic/ts/indent` and other stylistic rules
The [`@stylisic/ts/indent` rule](https://eslint.style/rules/ts/indent#ts-indent) helps ensure your codebase follows a consistent indentation pattern.
However this involves a _lot_ of computations across every single token in a file.
Across a large codebase, these can add up, and severely impact performance.
We recommend not using this rule, and instead using a tool like [`prettier`](https://www.npmjs.com/package/prettier) to enforce a standardized formatting.
See our [documentation on formatting](../../users/What_About_Formatting.mdx) for more information.
### `eslint-plugin-prettier`
This plugin surfaces Prettier formatting problems at lint time, helping to ensure your code is always formatted.
However this comes at a quite a large cost - in order to figure out if there is a difference, it has to do a Prettier format on every file being linted.
This means that each file will be parsed twice - once by ESLint, and once by Prettier.
This can add up for large codebases.
Instead of using this plugin, we recommend using Prettier's `--check` flag to detect if a file has not been correctly formatted.
For example, our CI is setup to run the following command automatically, which blocks PRs that have not been formatted:
```bash npm2yarn
npm run prettier --check .
```
See [Prettier's `--check` docs](https://prettier.io/docs/en/cli#--check) for more details.
### `eslint-plugin-import`
This is another great plugin that we use ourselves in this project.
However there are a few rules which can cause your lints to be really slow, because they cause the plugin to do its own parsing, and file tracking.
This double parsing adds up for large codebases.
There are many rules that do single file static analysis, but we provide the following recommendations.
We recommend you do not use the following rules, as TypeScript provides the same checks as part of standard type checking:
- `import/named`
- `import/namespace`
- `import/default`
- `import/no-named-as-default-member`
- `import/no-unresolved` (as long as you are using [`import` over `require`](/rules/no-require-imports))
The following rules do not have equivalent checks in TypeScript, so we recommend that you only run them at CI/push time, to lessen the local performance burden.
- `import/no-named-as-default`
- `import/no-cycle`
- `import/no-unused-modules`
- `import/no-deprecated`
#### `import/extensions` enforcing extensions are used
If you want to enforce file extensions are always used and you're **NOT** using `moduleResolution` `node16` or `nodenext`, then there's not really a good alternative for you, and you should continue using the `import/extensions` lint rule.
If you want to enforce file extensions are always used and you **ARE** using `moduleResolution` `node16` or `nodenext`, then you don't need to use the lint rule at all because TypeScript will automatically enforce that you include extensions!
#### `import/extensions` enforcing extensions are not used
On the surface `import/extensions` seems like it should be fast for this use case, however the rule isn't just a pure AST-check - it has to resolve modules on disk so that it doesn't false positive on cases where you are importing modules with an extension as part of their name (eg `foo.js` resolves to `node_modules/foo.js/index.js`, so the `.js` is required). This disk lookup is costly and thus makes the rule slow.
If your project doesn't use any `npm` packages with a file extension in their name, nor do you name your files with two extensions (like `bar.js.ts`), then this extra cost probably isn't worth it, and you can use a much simpler check using the [`no-restricted-syntax`](https://eslint.org/docs/latest/rules/no-restricted-syntax) lint rule.
The below config is several orders of magnitude faster than `import/extensions` as it does not do disk lookups, however it will false-positive on cases like the aforementioned `foo.js` module.
```js
function banImportExtension(extension) {
const message = `Unexpected use of file extension (.${extension}) in import`;
const literalAttributeMatcher = `Literal[value=/\\.${extension}$/]`;
return [
{
// import foo from 'bar.js';
selector: `ImportDeclaration > ${literalAttributeMatcher}.source`,
message,
},
{
// const foo = import('bar.js');
selector: `ImportExpression > ${literalAttributeMatcher}.source`,
message,
},
{
// type Foo = typeof import('bar.js');
selector: `TSImportType > TSLiteralType > ${literalAttributeMatcher}`,
message,
},
{
// const foo = require('foo.js');
selector: `CallExpression[callee.name = "require"] > ${literalAttributeMatcher}.arguments`,
message,
},
];
}
module.exports = {
// ... other config ...
rules: {
'no-restricted-syntax': [
'error',
...banImportExtension('js'),
...banImportExtension('jsx'),
...banImportExtension('ts'),
...banImportExtension('tsx'),
],
},
};
```
---
# TypeScript ESLint Documentation
# Source: https://raw.githubusercontent.com/typescript-eslint/typescript-eslint/main/docs/troubleshooting/typed-linting/index.mdx
# Path: docs/troubleshooting/typed-linting/index.mdx
---
id: index
title: Typed Linting
slug: /troubleshooting/typed-linting
---
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
## Editor ESLint reports become out-of-date after file changes
There is a known issue in at least VS Code with typed linting that files might have out-of-date lint errors after multiple updates to files on disk.
The root cause is that ESLint doesn't provide a way for editors to know about cross-file dependencies, such as type information.
This results in files receiving out-of-date type information when files they import from are changed.
You might see this as erroneous `no-unsafe-*` rule complaints on `any` or `error typed` values.
Other rules may be more subtly incorrect.
For now, the workaround is to run the _**Restart ESLint Server**_ command in VS Code (or an equivalent in other editors) when types get out of date.
See [ESLint does not re-compute cross-file information on file changes (microsoft/vscode-eslint#1774)](https://github.com/microsoft/vscode-eslint/issues/1774) for more information.
## How do I disable type-checked linting for a file?
Use [ESLint's configuration objects](https://eslint.org/docs/latest/use/configure/configuration-files#specifying-files-with-arbitrary-extensions) with our [`disable-type-checked`](../../users/Shared_Configurations.mdx#disable-type-checked) config to disable type checking for a `files` match that includes that file.
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 defineConfig(
// ... the rest of your config ...
{
files: ['**/*.js'],
extends: [tseslint.configs.disableTypeChecked],
},
);
```
```js title=".eslintrc.cjs"
module.exports = {
// ... the rest of your config ...
overrides: [
{
extends: ['plugin:@typescript-eslint/disable-type-checked'],
files: ['./**/*.js'],
},
],
};
```
Alternatively to disable type checking for files manually, you can set [`parserOptions: { project: false }`](../../packages/Parser.mdx#project) to an override for the files you wish to exclude.
## How can I disable type-aware linting for a set of files?
You can combine ESLint's [overrides](https://eslint.org/docs/latest/use/configure/configuration-files#configuration-based-on-glob-patterns) config in conjunction with our [`disable-type-checked`](../../users/Shared_Configurations.mdx#disable-type-checked) config to turn off type-aware linting on specific subsets of files.
```js title="eslint.config.mjs"
export default defineConfig(
eslint.configs.recommended,
tseslint.configs.recommendedTypeChecked,
tseslint.configs.stylisticTypeChecked,
{
languageOptions: {
parserOptions: {
projectService: true,
},
},
},
// Added lines start
{
files: ['**/*.js'],
extends: [tseslint.configs.disableTypeChecked],
},
// Added lines end
);
```
```js title=".eslintrc.js"
module.exports = {
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended-type-checked',
'plugin:@typescript-eslint/stylistic-type-checked',
],
plugins: ['@typescript-eslint'],
parser: '@typescript-eslint/parser',
parserOptions: {
projectService: true,
tsconfigRootDir: __dirname,
},
root: true,
// Added lines start
overrides: [
{
files: ['*.js'],
extends: ['plugin:@typescript-eslint/disable-type-checked'],
},
],
// Added lines end
};
```
:::info
If you use type-aware rules from other plugins, you will need to manually disable these rules or use a premade config they provide to disable them.
:::
## typescript-eslint thinks my variable is never nullish / is `any` / etc., but that is clearly not the case to me
Our type-aware rules almost always trust the type information provided by the TypeScript compiler. Therefore, an easy way to check if our rule is behaving correctly is to inspect the type of the variable in question, such as by hovering over it in your IDE.
If the IDE also shows that the type is never nullish / is `any`, you need to fix the type. A very common case is with the [`no-unnecessary-condition`](/rules/no-unnecessary-condition) rule. Take this code for example:
```ts
let condition = false;
const f = () => (condition = true);
f();
if (condition) {
//^^^^^^^^^ Unnecessary conditional, value is always falsy.
}
```
You can see that the type of `condition` is actually the literal type `false` by hovering over it in your IDE. In this case, typescript-eslint cannot possibly know better than TypeScript itself, so you need to fix the report by fixing the type, such as through an assertion (`let condition = false as boolean`).
If the IDE provides different type information from typescript-eslint's report, then make sure that the TypeScript setup used for your IDE, typescript-eslint, and `tsc` are the same: the same TypeScript version, the same type-checking compiler options, and the same files being included in the project. For example, if a type is declared in another file but that file is not included, the type will become `any`, and cause our `no-unsafe-*` rules to report.
## Are TypeScript project references supported?
Yes, but only with [`parserOptions.projectService`](../../packages/Parser.mdx#projectservice).
See [issue #2094 discussing project references](https://github.com/typescript-eslint/typescript-eslint/issues/2094) for more details.
## Project Service Issues
[`parserOptions.projectService`](../../packages/Parser.mdx#projectservice) is the recommended parser option to enable typed linting as of typescript-eslint v8.
It enforces projects generate type information for typed linting from the same `tsconfig.json` files used by editors such as VS Code.
### I get errors telling me "... was not found by the project service. Consider either including it in the tsconfig.json or including it in allowDefaultProject"
These errors are caused by attempting to use the project service to lint a file not explicitly included in its nearest `tsconfig.json`.
The project service will attempt to build type information for each file being linted using the nearest `tsconfig.json` on disk to that file.
If that `tsconfig.json` does not include the file, and the file isn't allowlisted in [`allowDefaultProject`](../../packages/parser#allowdefaultproject), then the project service will throw this error.
For each file being reported:
- If you **do not** want to lint the file:
- Use [one of the options ESLint offers to ignore files](https://eslint.org/docs/latest/user-guide/configuring/ignoring-code), such an `ignores` config key.
- If you **do** want to lint the file:
- If you **do not** want to lint the file with [type-aware linting](../../getting-started/Typed_Linting.mdx): [disable type-checked linting for that file](#how-do-i-disable-type-checked-linting-for-a-file).
- If you **do** want to lint the file with [type-aware linting](../../getting-started/Typed_Linting.mdx):
1. If possible, add the file to the closest `tsconfig.json`'s `include`. For example, allowing `.js` files:
```diff title="tsconfig.json"
"include": [
"src",
+ "*.js"
]
```
2. Otherwise, if you have a small number of "out of project" files, try setting [`projectService.allowDefaultProject`](../../packages/parser#allowdefaultproject).
3. If not, you can switch to [`parserOptions.project`](../../packages/Parser.mdx#project) for more fine-grained control of projects.
Note also:
- TSConfigs don't include `.js` files by default.
Enabling [`allowJs`](https://www.typescriptlang.org/tsconfig/#allowJs) or [`checkJs`](https://www.typescriptlang.org/tsconfig/#checkJs) is required to do so.
- The project service _only_ looks at `tsconfig.json` files.
It does not look at `tsconfig.eslint.json` or other coincidentally-similarly-named files.
If these steps don't work for you, please [file an issue on typescript-eslint's typescript-estree package](https://github.com/typescript-eslint/typescript-eslint/issues/new?assignees=&labels=enhancement%2Ctriage&projects=&template=07-enhancement-other.yaml&title=Enhancement%3A+%3Ca+short+description+of+my+proposal%3E) telling us your use case and why you need more out-of-project files linted.
Be sure to include a minimal reproduction we can work with to understand your use case!
### I get errors telling me "Having many files run with the default project is known to cause performance issues and slow down linting."
These errors are caused by attempting to use the project service to lint too many files not explicitly included in a `tsconfig.json` with its [`allowDefaultProject`](../../packages/parser#allowdefaultproject) option.
typescript-eslint allows up to 8 "out of project" files by default.
Each file causes a new TypeScript "program" to be built for each file it includes, which incurs a performance overhead _for each file_.
For each file being reported:
- If you **do not** want to lint the file:
- Use [one of the options ESLint offers to ignore files](https://eslint.org/docs/latest/user-guide/configuring/ignoring-code), such an `ignores` config key.
- If you **do** want to lint the file:
- If you **do not** want to lint the file with [type-aware linting](../../getting-started/Typed_Linting.mdx): [disable type-checked linting for that file](#how-do-i-disable-type-checked-linting-for-a-file).
- If you **do** want to lint the file with [type-aware linting](../../getting-started/Typed_Linting.mdx):
1. If possible, add the file to the closest `tsconfig.json`'s `include` instead of adding it to `allowDefaultProject`. For example, allowing `.js` files:
```diff title="tsconfig.json"
"include": [
"src",
+ "*.js"
]
```
2. If not, you can switch to [`parserOptions.project`](../../packages/Parser.mdx#project) for more fine-grained control of projects.
### I'd like to use TSConfigs other than `tsconfig.json`s for project service type information
Only the TSConfig path used for "out of project" files in [`allowDefaultProject`](../../packages/Parser.mdx#allowdefaultproject) can be customized.
Otherwise, only `tsconfig.json` files on disk will be read.
For example, instead of:
- `tsconfig.json`s for building (and, coincidentally, type information in editors)
- Separate TSConfig(s) like `tsconfig.eslint.json` for linting
Consider using:
- `tsconfig.json`s for linting (and, intentionally, the same type information in editors)
- Separate TSConfig(s) like `tsconfig.build.json` for building
The project service uses the same underlying TypeScript logic as editors such as VS Code.
Using only `tsconfig.json` for typed linting enforces that the types seen in your editor match what's used for linting.
## Traditional Project Issues
### I get errors telling me "ESLint was configured to run ... However, that TSConfig does not / none of those TSConfigs include this file"
These errors are caused by an ESLint config requesting type information be generated for a file that isn't included in the TypeScript configuration.
#### Fixing the Error
- If you **do not** want to lint the file:
- Use [one of the options ESLint offers to ignore files](https://eslint.org/docs/latest/user-guide/configuring/ignoring-code), namely a `.eslintignore` file, or `ignorePatterns` config.
- If you **do** want to lint the file:
- If you **do not** want to lint the file with [type-aware linting](../../getting-started/Typed_Linting.mdx):
- Use [ESLint's configuration objects](https://eslint.org/docs/latest/use/configure/configuration-files#specifying-files-with-arbitrary-extensions) with our [`disable-type-checked`](../../users/Shared_Configurations.mdx#disable-type-checked) config to disable type checking for just that type of file.
- If you **do** want to lint the file with [type-aware linting](../../getting-started/Typed_Linting.mdx):
- Check the `include` option of each of the TSConfigs that you provide to `parserOptions.project` - you must ensure that all files match an `include` glob, or else our tooling will not be able to find it.
- If the file is a `.cjs`, `.js`, or `.mjs` file, make sure [`allowJs`](https://www.typescriptlang.org/tsconfig#allowJs) is enabled.
- If your file shouldn't be a part of one of your existing tsconfigs (for example, it is a script/tool local to the repo), then consider creating a new tsconfig (we advise calling it `tsconfig.eslint.json`) in your project root which lists this file in its `include`. For an example of this, you can check out the configuration we previously used in this repo:
- [`tsconfig.eslint.json`](https://github.com/typescript-eslint/typescript-eslint/blob/958fecaef10a26792dc00e936e98cb19fd26d05f/tsconfig.eslint.json)
- [`eslint.config.mjs`](https://github.com/typescript-eslint/typescript-eslint/blob/958fecaef10a26792dc00e936e98cb19fd26d05f/.eslintrc.js)
#### More Details
This error may appear from the combination of two things:
- The ESLint configuration for the source file specifies at least one TSConfig file in `parserOptions.project`
- None of those TSConfig files includes the source file being linted
- Note that files with the same name and different extension may not be recognized by TypeScript: see [`parserOptions.project` docs](../../packages/parser/#project)
When TSConfig files are specified for parsing a source file, `@typescript-eslint/parser` will use the first TSConfig that is able to include that source file (per [aka.ms/tsconfig#include](https://www.typescriptlang.org/tsconfig#include)) to generate type information.
However, if no specified TSConfig includes the source file, the parser won't be able to generate type information.
This error most commonly happens on config files or similar that are not included in their project TSConfig(s).
For example, many projects have files like:
- An `.eslintrc.cjs` / `eslint.config.mjs` with `parserOptions.project: true`
- A `tsconfig.json` with `include: ["src"]`
In that case, viewing the file in an IDE with the ESLint extension will show the error notice that the file couldn't be linted because it isn't included in `tsconfig.json`.
See our docs on [type aware linting](../../getting-started/Typed_Linting.mdx) for more information.
### I get errors telling me "The file must be included in at least one of the projects provided"
You're using an outdated version of `@typescript-eslint/parser`.
Update to the latest version to see a more informative version of this error message, explained [above](#i-get-errors-telling-me-eslint-was-configured-to-run--however-that-tsconfig-does-not--none-of-those-tsconfigs-include-this-file 'backlink to I get errors telling me ESLint was configured to run ...').
### Can I customize the TSConfig used for the project?
Yes, but it's not recommended in most configurations.
`parserOptions.projectService` uses the same "project service" APIs used by editors such as VS Code to generate TypeScript's type information.
Using a different TSConfig runs the risk of providing different types for typed linting than what your editor or `tsc` see.
If you absolutely must, the `parserOptions.project` option can be used instead of `parserOptions.projectService` with either:
- `true`: to always use `tsconfig.json`s nearest to source files
- `string | string[]`: any number of glob paths to match TSConfig files relative to `parserOptions.tsconfigRootDir`, or the current working directory if that is not provided
For example, if you use a specific `tsconfig.eslint.json` for linting, you'd specify:
```js title="eslint.config.mjs"
export default defineConfig({
// ...
languageOptions: {
parserOptions: {
project: './tsconfig.eslint.json',
},
},
// ...
});
```
```js title=".eslintrc.js"
module.exports = {
// ...
parserOptions: {
project: './tsconfig.eslint.json',
tsconfigRootDir: __dirname,
},
// ...
};
```
See [the `@typescript-eslint/parser` `project` docs for more details](../../packages/Parser.mdx#project).
:::note
If your project is a multi-package monorepo, see [Troubleshooting > Typed Linting > Monorepos](./Monorepos.mdx).
:::
---
# TypeScript ESLint Documentation
# Source: https://raw.githubusercontent.com/typescript-eslint/typescript-eslint/main/docs/users/Dependency_Versions.mdx
# Path: docs/users/Dependency_Versions.mdx
---
id: dependency-versions
title: Dependency Versions
---
import rootPackageJson from '../../package.json';
import eslintPluginPackageJson from '../../packages/eslint-plugin/package.json';
## ESLint
The version range of ESLint currently supported is{' '}
{eslintPluginPackageJson.peerDependencies.eslint}.
We generally support at least the latest two major versions of ESLint; though sometimes we may restrict this if the APIs change too much between major releases.
## Node
The version range of NodeJS currently supported is{' '}
{eslintPluginPackageJson.engines.node}.
We make an effort to support Active LTS and Maintenance LTS release statuses of Node according to [Node's release document](https://github.com/nodejs/release#release-schedule).
Support for specific Current status releases are considered periodically.
## TypeScript
The version range of TypeScript currently supported is{' '}
{rootPackageJson.devDependencies.typescript}.
We mirror [DefinitelyTyped's version support window](https://github.com/DefinitelyTyped/DefinitelyTyped/#support-window) - meaning we only support versions of TypeScript less than 2 years old.
You may find that our tooling works on older TypeScript versions however we provide no guarantees and **_we will not accept issues against unsupported versions_**.
We will always endeavor to support the latest stable version of TypeScript.
Sometimes, but not always, changes in TypeScript will not require breaking changes in this project, and so we are able to support more than one version of TypeScript.
In some cases, we may even be able to support additional pre-releases (i.e. betas and release candidates) of TypeScript, but only if doing so does not require us to compromise on support for the latest stable version.
### Supporting New TypeScript Releases
With each new TypeScript release we file an issue to track the changes in the new version. The issue should always be pinned, and you can also [find the issues by searching for issues tagged with "New TypeScript Version"](https://github.com/typescript-eslint/typescript-eslint/issues?q=is%3Aissue+label%3A%22New+TypeScript+Version%22+sort%3Acreated-desc). If the issue is open, we do not have official support yet - please be patient.
In terms of what versions we support:
- We do not support the `beta` releases.
- We _generally_ do not officially support the `rc` releases.
- We endeavor to support the latest stable TypeScript versions as soon as possible after the release.
Generally we will begin working on supporting the next release when the `rc` version is released.
### Version Warning Logs
Note that our packages have an open `peerDependency` requirement in order to allow for experimentation on newer/beta versions of TypeScript.
If you use a non-supported version of TypeScript, the parser will log a warning to the console.
If you want to disable this warning, you can configure this in your `parserOptions`.
See: [Packages > Parser > `warnOnUnsupportedTypeScriptVersion`](../packages/Parser.mdx#warnonunsupportedtypescriptversion).
## Dependant Version Upgrades
See [Maintenance > Dependent Version Upgrades](../maintenance/pull-requests/Dependency_Version_Upgrades.mdx) for maintenance steps to update these versions.
---
# TypeScript ESLint Documentation
# Source: https://raw.githubusercontent.com/typescript-eslint/typescript-eslint/main/docs/users/Releases.mdx
# Path: docs/users/Releases.mdx
---
id: releases
sidebar_label: Releases
title: Releases
---
import useIsBrowser from '@docusaurus/useIsBrowser';
export function LocalTimeOfRelease() {
const isBrowser = useIsBrowser();
if (!isBrowser) {
// An arbitrary Monday at 17:00 UTC.
const arbitraryMonday = new Date('1970-01-05T17:00Z');
return arbitraryMonday.toLocaleTimeString('en-US', {
hour: 'numeric',
minute: '2-digit',
timeZoneName: 'short',
timeZone: 'UTC',
});
}
const now = new Date();
const daysAgoToMonday = (now.getUTCDay() + 6) % 7;
// Calculate the previous Monday at 17:00 UTC.
const previousReleaseDate = new Date(
Date.UTC(
now.getUTCFullYear(),
now.getUTCMonth(),
now.getUTCDate() - daysAgoToMonday,
17,
),
);
// This will happen if the current time is before 17:00 UTC on Monday.
if (previousReleaseDate > now) {
previousReleaseDate.setUTCDate(previousReleaseDate.getUTCDate() - 7);
}
// Next release is 7 days later.
const nextReleaseDate = new Date(previousReleaseDate.getTime());
nextReleaseDate.setUTCDate(previousReleaseDate.getUTCDate() + 7);
// If we're near a DST time change, we want to display the time of the release that has the same UTC offset as now.
// If, for some reason, neither does, just display the local time of the next release.
const releaseWithSameUtcOffset =
[nextReleaseDate, previousReleaseDate].find(
date => date.getTimezoneOffset() === now.getTimezoneOffset(),
) ?? nextReleaseDate;
const formatted = releaseWithSameUtcOffset.toLocaleTimeString('en-US', {
hour: 'numeric',
minute: '2-digit',
timeZoneName: 'short',
});
// Specify the day of week if it's not a Monday.
const dayNames = [
'Sunday',
'Monday',
'Tuesday',
'Wednesday',
'Thursday',
'Friday',
'Saturday',
];
if (
releaseWithSameUtcOffset.getDay() !== releaseWithSameUtcOffset.getUTCDay()
) {
return `${dayNames[releaseWithSameUtcOffset.getDay()]}s at ${formatted}`;
}
return formatted;
}
## Latest
We release a latest version every Monday at 17:00 UTC () using the latest commit to `main` at that time. This release is performed automatically by a Github action located in a private repository. This release goes to the standard `latest` tag on npm.
See [Versioning](./Versioning.mdx) for how the version number is calculated.
If there have been no commits that impact public-facing packages then a patch-level release shall be released.
Latest releases shall only ever be "minor" or "patch" releases.
### Release Notes
Every release is documented on the [Github Release page](https://github.com/typescript-eslint/typescript-eslint/releases).
These release notes will list the PRs included in the release.
## Canary
We release a canary version for each commit to `main` that passes all required checks. This release is performed automatically by the [`publish_canary_version` step](https://github.com/typescript-eslint/typescript-eslint/blob/5feb2dba9da2bd5e233451b7b0f1c99414b5aef9/.github/workflows/ci.yml#L234-L263). So **you never need to wait for a new stable version to make use of any updates**.
This release goes to the `canary` tag on npm and it is versioned as an incremental canary patch release on top of the current `latest` version. I.e. if the current version is `5.6.1`, then the first canary version will be `5.6.2-alpha.0`, the second `5.6.2-alpha.1`, and so on.
:::note
The only exception to the automated publishes described above is when we are in the final phases of creating the next major version of the libraries - e.g. going from `1.x.x` to `2.x.x`.
During these periods, we manually publish `canary` releases until we are happy with the release and promote it to `latest`.
:::
### Installing Canary Versions
To try out the latest canary versions of typescript-eslint, install `@typescript-eslint/eslint-plugin@canary` and `@typescript-eslint/parser@canary`.
Note that npm may need a `--force` to override version requirements.
```bash npm2yarn
npm i @typescript-eslint/eslint-plugin@canary @typescript-eslint/parser@canary --save-dev --force
```
## Major Releases
We currently do not have a set schedule around when major releases shall be performed; instead they are done as the need arises.
We keep a backlog of breaking issues as a milestone on GitHub that is named in the form `${major}.0.0`.
When we do do a major release, we release a release candidate version to the `rc-v${major}` tag on npm for each commit to the major branch.
See [Maintenance > Releases](../maintenance/Releases.mdx#major-releases) for steps to perform a major release.
## Out-of-Band Releases
We will do releases "out-of-band" (outside the [latest](#latest) schedule) for rare emergencies.
We assess need on a case-by-case basis though generally an emergency is defined as a critical regression specifically introduced in the latest release.
These releases are done manually by a maintainer with the required access privileges.
## Older Versions
Older major versions of typescript-eslint are never maintained or supported.
They may crash with the latest versions of TypeScript.
Using the latest version of typescript-eslint is strongly recommended for getting the latest rule features and fixes, supporting the latest TypeScript features and syntax, and continuous performance and stability improvements.
### Back-Porting Releases
We **_do not_** back port releases to previously released major/minor versions.
We only ever release forward.
### Old Release Documentation
You can find the last version of some older major versions under their dedicated branch deploys:
- v7: [v7--typescript-eslint.netlify.app](https://v7--typescript-eslint.netlify.app)
- v6: [v6--typescript-eslint.netlify.app](https://v6--typescript-eslint.netlify.app)
Note that older documentation pages may contain outdated information and links.
We strongly recommend using the latest version of typescript-eslint and its documentation.
---
# TypeScript ESLint Documentation
# Source: https://raw.githubusercontent.com/typescript-eslint/typescript-eslint/main/docs/users/Shared_Configurations.mdx
# Path: docs/users/Shared_Configurations.mdx
---
id: configs
title: Shared Configs
---
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
[ESLint shareable configurations](https://eslint.org/docs/latest/developer-guide/shareable-configs) exist to provide a comprehensive list of rules settings that you can start with.
`@typescript-eslint/eslint-plugin` includes built-in configurations you can extend from to pull in the recommended starting rules.
> With the exception of `all`, `strict`, and `strict-type-checked`, all configurations are considered "stable".
> Rule additions and removals are treated as breaking changes and will only be done in major version bumps.
## Getting Started
See [Getting Started > Quickstart](../getting-started/Quickstart.mdx) first to set up your ESLint configuration file.
[Packages > typescript-eslint](../packages/TypeScript_ESLint.mdx) includes more documentation on the `tseslint` helper.
```js title="eslint.config.mjs"
// @ts-check
import eslint from '@eslint/js';
import { defineConfig } from 'eslint/config';
import tseslint from 'typescript-eslint';
export default defineConfig(
eslint.configs.recommended,
tseslint.configs.recommended,
);
```
### Projects Without Type Checking
If your project does not enable [typed linting](../getting-started/Typed_Linting.mdx), we suggest enabling the [`recommended`](#recommended) and [`stylistic`](#stylistic) configurations to start:
```js title="eslint.config.mjs"
export default defineConfig(
eslint.configs.recommended,
tseslint.configs.recommended,
tseslint.configs.stylistic,
);
```
```js title=".eslintrc.js"
module.exports = {
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
'plugin:@typescript-eslint/stylistic',
],
};
```
> If a majority of developers working on your project are comfortable with TypeScript and typescript-eslint, consider replacing `recommended` with `strict`.
### Projects With Type Checking
If your project enables [typed linting](../getting-started/Typed_Linting.mdx), we suggest enabling the [`recommended-type-checked`](#recommended-type-checked) and [`stylistic-type-checked`](#stylistic-type-checked) configurations to start:
:::note
To use type-checking, you also need to configure `languageOptions.parserOptions` as shown in [typed linting docs](../getting-started/Typed_Linting.mdx).
:::
```js title="eslint.config.mjs"
export default defineConfig(
eslint.configs.recommended,
// Added lines start
tseslint.configs.recommendedTypeChecked,
tseslint.configs.stylisticTypeChecked,
// Added lines end
// Other configuration...
);
```
```js title=".eslintrc.js"
module.exports = {
extends: [
'eslint:recommended',
// Added lines start
'plugin:@typescript-eslint/recommended-type-checked',
'plugin:@typescript-eslint/stylistic-type-checked',
// Added lines end
],
// Other configuration...
};
```
> If a majority of developers working on your project are comfortable with TypeScript and typescript-eslint, consider replacing `recommended-type-checked` with `strict-type-checked`.
## Recommended Configurations
We recommend that most projects should extend from one of:
- [`recommended`](#recommended): Recommended rules for code correctness that you can drop in without additional configuration.
- [`recommended-type-checked`](#recommended-type-checked): Contains `recommended` + additional recommended rules that require type information.
- [`strict`](#strict): Contains `recommended` + additional strict rules that can also catch bugs but are more opinionated than recommended rules.
- [`strict-type-checked`](#strict-type-checked): Contains `strict` + additional strict rules require type information.
Additionally, we provide a [`stylistic`](#stylistic) config that enforces concise and consistent code.
We recommend that most projects should extend from either:
- [`stylistic`](#stylistic): Stylistic rules you can drop in without additional configuration.
- [`stylistic-type-checked`](#stylistic-type-checked): Contains `stylistic` + additional stylistic rules that require type information.
:::note
These configurations are our recommended starting points, but **you don't need to use them as-is**.
ESLint allows configuring own rule settings on top of extended configurations.
See [ESLint's Configuring Rules docs](https://eslint.org/docs/user-guide/configuring/rules#using-configuration-files).
:::
### `recommended`
Recommended rules for code correctness that you can drop in without additional configuration.
These rules are those whose reports are almost always for a bad practice and/or likely bug.
`recommended` also disables core ESLint rules known to conflict with typescript-eslint rules or cause issues in TypeScript codebases.
{/* prettier-ignore */}
```js title="eslint.config.mjs"
export default defineConfig(
tseslint.configs.recommended,
);
```
```js title=".eslintrc.js"
module.exports = {
extends: ['plugin:@typescript-eslint/recommended'],
};
```
See [the source code for the `recommended` config](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/src/configs/eslintrc/recommended.ts) for the exact contents.
### `recommended-type-checked`
Contains all of `recommended` along with additional recommended rules that require type information.
Rules newly added in this configuration are similarly useful to those in `recommended`.
{/* prettier-ignore */}
```js title="eslint.config.mjs"
export default defineConfig(
tseslint.configs.recommendedTypeChecked,
);
```
```js title=".eslintrc.js"
module.exports = {
extends: ['plugin:@typescript-eslint/recommended-type-checked'],
};
```
See [the source code for the `recommended-type-checked` config](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/src/configs/eslintrc/recommended-type-checked.ts) for the exact contents.
### `strict`
Contains all of `recommended`, as well as additional strict rules that can also catch bugs.
Rules added in `strict` are more opinionated than recommended rules and might not apply to all projects.
{/* prettier-ignore */}
```js title="eslint.config.mjs"
export default defineConfig(
tseslint.configs.strict,
);
```
```js title=".eslintrc.js"
module.exports = {
extends: ['plugin:@typescript-eslint/strict'],
};
```
Some rules also enabled in `recommended` default to more strict settings in this configuration.
See [the source code for the `strict` config](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/src/configs/eslintrc/strict.ts) for the exact contents.
:::tip
We recommend a TypeScript project extend from `plugin:@typescript-eslint/strict` only if a nontrivial percentage of its developers are highly proficient in TypeScript.
:::
:::warning
This configuration is not considered "stable" under Semantic Versioning (semver).
Its enabled rules and/or their options may change outside of major version updates.
:::
### `strict-type-checked`
Contains all of `recommended`, `recommended-type-checked`, and `strict`, along with additional strict rules that require type information.
Rules newly added in this configuration are similarly useful (and opinionated) to those in `strict`.
{/* prettier-ignore */}
```js title="eslint.config.mjs"
export default defineConfig(
tseslint.configs.strictTypeChecked,
);
```
```js title=".eslintrc.js"
module.exports = {
extends: ['plugin:@typescript-eslint/strict-type-checked'],
};
```
Some rules also enabled in `recommended-type-checked` default to more strict settings in this configuration.
See [the source code for the `strict-type-checked` config](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/src/configs/eslintrc/strict-type-checked.ts) for the exact contents.
:::tip
We recommend a TypeScript project extend from `plugin:@typescript-eslint/strict-type-checked` only if a nontrivial percentage of its developers are highly proficient in TypeScript.
:::
:::warning
This configuration is not considered "stable" under Semantic Versioning (semver).
Its enabled rules and/or their options may change outside of major version updates.
:::
### `stylistic`
Rules considered to be best practice for modern TypeScript codebases, but that do not impact program logic.
These rules are generally opinionated about enforcing simpler code patterns.
{/* prettier-ignore */}
```js title="eslint.config.mjs"
export default defineConfig(
tseslint.configs.stylistic,
);
```
```js title=".eslintrc.js"
module.exports = {
extends: ['plugin:@typescript-eslint/stylistic'],
};
```
Note that `stylistic` does not replace `recommended` or `strict`.
`stylistic` adds additional rules.
See [the source code for the `stylistic` config](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/src/configs/eslintrc/stylistic.ts) for the exact contents.
### `stylistic-type-checked`
Contains all of `stylistic`, along with additional stylistic rules that require type information.
Rules newly added in this configuration are similarly opinionated to those in `stylistic`.
{/* prettier-ignore */}
```js title="eslint.config.mjs"
export default defineConfig(
tseslint.configs.stylisticTypeChecked,
);
```
```js title=".eslintrc.js"
module.exports = {
extends: ['plugin:@typescript-eslint/stylistic-type-checked'],
};
```
Note that `stylistic-type-checked` does not replace `recommended-type-checked` or `strict-type-checked`.
`stylistic-type-checked` adds additional rules.
See [the source code for the `stylistic-type-checked` config](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/src/configs/eslintrc/stylistic-type-checked.ts) for the exact contents.
## Other Configurations
typescript-eslint includes a few utility configurations.
### `all`
Enables each the rules provided as a part of typescript-eslint.
Note that many rules are not applicable in all codebases, or are meant to be configured.
See [the source code for the `all` config](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/src/configs/eslintrc/all.ts) for the exact contents.
:::warning
We do not recommend TypeScript projects extend from `plugin:@typescript-eslint/all`.
Many rules conflict with each other and/or are intended to be configured per-project.
:::
:::warning
This configuration is not considered "stable" under Semantic Versioning (semver).
Its enabled rules and/or their options may change outside of major version updates.
:::
### `base`
A minimal ruleset that sets only the required parser and plugin options needed to run typescript-eslint.
We don't recommend using this directly; instead, extend from an earlier recommended rule.
This config is automatically included if you use any of the recommended configurations.
See [the source code for the `base` config](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/src/configs/eslintrc/base.ts) for the exact contents.
### `disable-type-checked`
A utility ruleset that will disable type-aware linting and all type-aware rules available in our project.
This config is useful if you'd like to have your base config concerned with type-aware linting, and then conditionally use [overrides](https://eslint.org/docs/latest/use/configure/configuration-files#configuration-based-on-glob-patterns) to disable type-aware linting on specific subsets of your codebase.
See [the source code for the `disable-type-checked` config](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/src/configs/eslintrc/disable-type-checked.ts) for the exact contents.
:::info
If you use type-aware rules from other plugins, you will need to manually disable these rules or use a premade config they provide to disable them.
:::
```js title="eslint.config.mjs"
export default defineConfig(
eslint.configs.recommended,
tseslint.configs.recommendedTypeChecked,
{
languageOptions: {
parserOptions: {
projectService: true,
},
},
},
// Added lines start
{
files: ['**/*.js'],
extends: [tseslint.configs.disableTypeChecked],
},
// Added lines end
);
```
```js title=".eslintrc.js"
module.exports = {
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended-type-checked',
],
parser: '@typescript-eslint',
parserOptions: {
projectService: true,
__tsconfigRootDir: __dirname,
},
root: true,
// Added lines start
overrides: [
{
files: ['**/*.js'],
extends: ['plugin:@typescript-eslint/disable-type-checked'],
},
],
// Added lines end
};
```
:::warning
This configuration is not considered "stable" under Semantic Versioning (semver).
Its enabled rules and/or their options may change outside of major version updates.
:::
### `eslint-recommended`
This ruleset is meant to be used after extending `eslint:recommended`.
It disables core ESLint rules that are already checked by the TypeScript compiler.
Additionally, it enables rules that promote using the more modern constructs TypeScript allows for.
```js title="eslint.config.mjs"
export default defineConfig(
eslint.configs.recommended,
tseslint.configs.eslintRecommended,
);
```
```js title=".eslintrc.js"
module.exports = {
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/eslint-recommended',
],
};
```
This config is automatically included if you use any of the recommended configurations.
See [the source code for the `eslint-recommended` config](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/src/configs/eslint-recommended-raw.ts) for the exact contents.
### `recommended-type-checked-only`
A version of `recommended` that _only_ contains type-checked rules and disables of any corresponding core ESLint rules.
This config plus `recommended` is equivalent to `recommended-type-checked`.
```js title=".eslintrc.js"
module.exports = {
extends: ['plugin:@typescript-eslint/recommended-type-checked-only'],
};
```
See [the source code for the `recommended-type-checked-only` config](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/src/configs/eslintrc/recommended-type-checked-only.ts) for the exact contents.
### `strict-type-checked-only`
A version of `strict` that _only_ contains type-checked rules and disables of any corresponding core ESLint rules.
This config plus `strict` is equivalent to `strict-type-checked`.
```js title=".eslintrc.js"
module.exports = {
extends: ['plugin:@typescript-eslint/strict-type-checked-only'],
};
```
See [the source code for the `strict-type-checked-only` config](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/src/configs/eslintrc/strict-type-checked-only.ts) for the exact contents.
:::warning
This configuration is not considered "stable" under Semantic Versioning (semver).
Its enabled rules and/or their options may change outside of major version updates.
:::
### `stylistic-type-checked-only`
A version of `stylistic` that _only_ contains type-checked rules and disables of any corresponding core ESLint rules.
This config plus `stylistic` is equivalent to `stylistic-type-checked`.
```js title=".eslintrc.js"
module.exports = {
extends: ['plugin:@typescript-eslint/stylistic-type-checked-only'],
};
```
See [the source code for the `stylistic-type-checked-only` config](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/src/configs/eslintrc/stylistic-type-checked-only.ts) for the exact contents.
## Suggesting Configuration Changes
If you feel strongly that a specific rule should (or should not) be one of these configurations, please [file an issue](https://github.com/typescript-eslint/typescript-eslint/issues/new?assignees=&labels=package%3A+eslint-plugin%2Cpreset+config+change%2Ctriage&template=09-config-change.yaml&title=Configs%3A+%3Ca+short+description+of+my+proposal%3E) along with a **detailed** argument explaining your reasoning.
## Formatting
None of the preset configs provided by typescript-eslint enable formatting rules (rules that only serve to enforce code whitespace and other trivia).
We strongly recommend you use Prettier or an equivalent for formatting your code, not ESLint formatting rules.
See [What About Formatting? > Suggested Usage](./What_About_Formatting.mdx#suggested-usage---prettier).
---
# TypeScript ESLint Documentation
# Source: https://raw.githubusercontent.com/typescript-eslint/typescript-eslint/main/docs/users/Versioning.mdx
# Path: docs/users/Versioning.mdx
---
id: versioning
title: Versioning
---
We follow [semantic versioning (semver)](https://semver.org).
This page exists to help set guidelines around what we consider to fall within each of the semver categories.
All of the packages in this project are published with the same version number to make it easier to coordinate both releases and installations.
## Breaking Changes
When considering whether a change should be counted as "breaking" we first need to consider what package(s) it impacts. For example breaking changes for the parser packages have a different standard to those for the ESLint plugins. This is because not only do they have _very_ different API surfaces, they also are consumed in very different ways.
Please note that the lists provided below are non-exhaustive and are intended to serve as examples to help guide maintainers when planning and reviewing changes.
### `ast-spec` and `visitor-keys`
A change to the AST **_shall_** be considered breaking if it:
- Removes or renames an existing AST Node.
- Removes or renames an existing property on an AST Node.
- Changes a type in a non-refining way (i.e. `string` to `number`).
A change to the AST **_shall not_** be considered breaking if it:
- Adds a new property to the AST.
- Adds a new node type to the AST.
- Adds a new node type to an existing union type.
- Refines a type to be more specific (i.e. `string` to `'literal' | 'union'`).
- Removes a type from a union that was erroneously added and did not match the runtime AST.
### `eslint-plugin`
A change to the plugins **_shall_** be considered breaking if it will require the user to change their config. More specifically:
- Removes or renames an option.
- Changes the default option of a rule.
- Changes a rule's schema to be stricter.
- Consumes type information to a rule that did not previously consume it.
- Removes or renames a rule.
- Changes any of the recommended configurations.
- Changes the default behavior of a rule in such a way that causes new reports in a large set of cases in an average codebase.
A change to the plugins **_shall not_** be considered breaking if it:
- Adds an option that by default does not remove existing functionality.
- Adds a rule.
- Deprecates a rule.
- Adds additional checks to an existing rule that causes new reports in a small-to-medium set of cases in an average codebase.
- Refactors a rule's code in a way that does not introduce additional reports.
- Changes to a rule's description or other metadata.
- Adds a fixer or suggestion fixer.
- Removes a fixer or suggestion fixer.
- Fixes incorrect behavior in a rule that may or may not introduce additional reports.
#### `parser`, `typescript-estree`, `scope-manager`, `types`, `type-utils`, `utils`
A change to these packages **_shall_** be considered breaking if it:
- Changes the API surface in a backwards-incompatible way (remove or rename functions, types, etc).
A change to these packages **_shall not_** be considered breaking if it:
- Adds to the API surface (add functions, types, etc).
- Deprecates parts of the API surface.
- Adds **_optional_** arguments to functions or properties to input types.
- Adds additional properties to output types.
- Adds documentation in the form of JSDoc comments.
### Internal packages
Any packages in this project that are not part of our public API surface (such as `eslint-plugin-internal` or `website`) shall not be considered when calculating new package versions.
---
# TypeScript ESLint Documentation
# Source: https://raw.githubusercontent.com/typescript-eslint/typescript-eslint/main/docs/users/What_About_Formatting.mdx
# Path: docs/users/What_About_Formatting.mdx
---
id: what-about-formatting
title: What About Formatting?
---
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
We recommend against using ESLint for formatting.
We recommend using [Prettier](https://prettier.io), [dprint](https://dprint.dev), or an equivalent instead.
## Formatters vs. Linters
**Formatters** are tools that verify and correct whitespace issues in code, such as spacing and newlines.
Formatters typically run very quickly because they are only concerned with changing whitespace, not code logic or naming.
**Linters** are tools that verify and correct logical and non-whitespace style issues in code, such as naming consistency and bug detection.
Linters often take seconds or more to run because they apply many logical rules to code.
### Problems with Using Linters as Formatters
Linters are designed to run in a parse, check, report, fix cycle. This means that there is a lot of intermediate work that needs to be done before a linter can fix a formatting issue with your code.
Additionally linters typically run each rule isolated from one another. This has several problems with it such as:
- any two lint rules can't share config, meaning one lint rule's fixer might introduce a violation of another lint rule's fixer (eg one lint rule might use the incorrect indentation character).
- lint rule fixers can conflict (apply to the same code range), forcing the linter to perform an additional cycle to attempt to apply a fixer to a clean set of code.
These problems cause a linter to be much slower - which can be much more of a problem in projects that enable [typed linting](../getting-started/Typed_Linting.mdx).
Formatting with a linter is also much less consistent and less able to handle edge-cases than a purpose-built formatter.
The maintenance cost of formatting-related lint rules is typically very high as a result.
Modern formatters such as Prettier are architected in a way that applies formatting to all code regardless of original formatting.
This design allows formatters to be much more comprehensive and consistent at much lower maintenance cost than linters.
### Suggested Usage - Prettier
Neither typescript-eslint nor ESLint core enable any formatting-related rules in any recommended presets.
However, some third party plugin configurations may still enable that bad practice.
If you see formatting rules enabled in your ESLint configuration, we recommend using [`eslint-config-prettier`](https://github.com/prettier/eslint-config-prettier) to disable formatting rules in your ESLint configuration.
You can then configure your formatter separately from ESLint.
Using this config by adding it to the end of your `extends`:
```js title="eslint.config.mjs"
// @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 defineConfig(
eslint.configs.recommended,
tseslint.configs.recommended,
someOtherConfig,
// Add this line
prettierConfig,
);
```
```js title=".eslintrc.js"
/* eslint-env node */
module.exports = {
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
'other-configuration-that-enables-formatting-rules',
// Add this line
'prettier',
],
parser: '@typescript-eslint/parser',
plugins: ['@typescript-eslint'],
root: true,
};
```
Note that even if you use a formatter other than `prettier`, you can use `eslint-config-prettier` as it exclusively turns **off** all formatting rules.
#### `eslint-plugin-prettier`
`eslint-config-prettier` is not the same as [`eslint-plugin-prettier`](https://github.com/prettier/eslint-plugin-prettier).
- The _config_ only disables rules from core and other plugins.
- The _plugin_ loads and runs Prettier inside ESLint.
Running Prettier inside ESLint can be slow: see [Performance Troubleshooting > `eslint-plugin-prettier`](../troubleshooting/typed-linting/Performance.mdx#eslint-plugin-prettier).
However, because it doesn't re-implement Prettier's logic in ESLint, the caveats mentioned about using linters for formatting don't apply to `eslint-plugin-prettier` either.
## ESLint Core and Formatting
Most lint rules fall into one of two to three categories:
- **Logical**: Rules that care about the logic in runtime behavior of code (such as missing `await`s or invalid logical checks).
- **Stylistic**: Rules that care about style concerns which do impact runtime behavior of code, but generally not logic. These are mostly around naming or which roughly-equivalent syntax constructs to use (such as function declarations vs. arrow functions).
- **Formatting**: Stylistic rules that care only about trivia (semicolons, whitespace, etc.) without impacting the runtime behavior of the code. These rules conflict with dedicated formatters such as Prettier.
Per [ESLint's 2020 Changes to Rule Policies blog post](https://eslint.org/blog/2020/05/changes-to-rules-policies#what-are-the-changes), ESLint itself has moved away from _stylistic_ rules, including _formatting_ rules:
> Stylistic rules are frozen - we won't be adding any more options to stylistic rules.
> We've learned that there's no way to satisfy everyone's personal preferences, and most of the rules already have a lot of difficult-to-understand options.
> Stylistic rules are those related to spacing, conventions, and generally anything that does not highlight an error or a better way to do something.
We mirror the ESLint team's move away from _formatting_ and _stylistic_ rules.
With the exception of bug fixes, no new formatting- or stylistic-related pull requests will be accepted into typescript-eslint.
:::note
The [`stylistic` configurations](../users/Shared_Configurations.mdx#stylistic) are not deprecated or recommended-against.
We'll continue to include those configs and their rules to help enforce TypeScript-related stylistic consistency for the foreseeable future.
:::
## `eslint-stylistic`
The downside of using a comprehensive formatter for formatting is that it will strictly apply opinions to code.
Although you can [ignore code in Prettier](https://prettier.io/docs/en/ignore.html) and other formatters, including inline such as with [`// prettier-ignore` comments](https://prettier.io/docs/en/ignore.html#javascript), formatters are much more opinionated than lint rules.
The [`eslint-stylistic`](https://eslint.style) project provides an ESLint plugin containing _formatting_ and _stylistic_ rules.
That plugin can serve as your formatter if you strongly prefer not to use a dedicated formatter.
See [ESLint Stylistic > Why?](https://eslint.style/guide/why) for more details on that project's motivation, and [ESLint Stylistic > Getting Started](https://eslint.style/guide/getting-started) for how to set it up.
---
# TypeScript ESLint Documentation
# Source: https://raw.githubusercontent.com/typescript-eslint/typescript-eslint/main/docs/users/What_About_TSLint.mdx
# Path: docs/users/What_About_TSLint.mdx
---
id: what-about-tslint
title: What About TSLint?
---
TSLint was a linter equivalent to ESLint that was written specifically to work directly on TypeScript code.
**TSLint is deprecated** and you should use `typescript-eslint` instead.
## Migrating from TSLint to ESLint
The standard tool to convert a TSLint configuration to the equivalent ESLint configuration is [`tslint-to-eslint-config`](https://github.com/typescript-eslint/tslint-to-eslint-config).
If you are still using TSLint, we strongly recommend you use this tool to switch.
You can look at [the alternatives list](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/TSLINT_RULE_ALTERNATIVES.md) for an up to date overview of how TSLint rules compare to the ones in this package.
There is also the ultimate fallback option of using both linters together for a while during your transition if you
absolutely have to by using TSLint _within_ ESLint.
For this option, check out [`@typescript-eslint/eslint-plugin-tslint`](../packages/ESLint_Plugin_TSLint.mdx).
## Why Deprecate TSLint?
One advantage of TSLint over ESLint was that there was no tooling required to reconcile differences between JavaScript and TypeScript syntax.
Unfortunately, that meant TSLint couldn't reuse any of the previous work which has been done in the JavaScript ecosystem around ESLint.
TSLint had to reimplement everything from editor extensions to auto-fixing to rules.
TSLint's backers announced in 2019 that **they would be deprecating TSLint in favor of supporting `typescript-eslint`** in order to benefit the community.
You can read more about that here: https://medium.com/palantir/tslint-in-2019-1a144c2317a9.
The TypeScript team also migrated the TypeScript codebase from TSLint to `typescript-eslint`, and they have been supporters of this project.
See more details at https://github.com/microsoft/TypeScript/issues/30553.
---
# TypeScript ESLint Documentation
# Source: https://raw.githubusercontent.com/typescript-eslint/typescript-eslint/main/docs/users/index.mdx
# Path: docs/users/index.mdx
---
id: index
title: Users
---
These are the user guides to consuming the typescript-eslint tooling.
It's intended for users who want to consume our tools.
:::info Welcome!
If you're reading this as a new user: welcome to the community!
We're happy to have you! ❤️🔥
:::