"Typed linting", or enabling ESLint rules to tap into the power of the TypeScript type checker, is one of the best parts of typescript-eslint. But enabling the type checker in repositories with multiple tsconfig.json
files can be annoying to set up. Even worse, specifying the wrong include paths could result in incorrect rule reports and/or unexpectedly slow lint times.
Improving the setup experience for typed lint rules has been a long-standing goal for typescript-eslint. One long-standing feature request for that experience has been to support automatically detecting TSConfigs for developers. We're happy to say that we now support that by setting parserOptions.project
equal to true
in ESLint configurations.
This post will explain what life was like before, what's changed, and what's coming next. 🎉
The Problem With ProjectsThe @typescript-eslint/parser
package is what enables ESLint to parse TypeScript source files. It converts raw TypeScript code into an "AST" format. When parserOptions.project
is specified, it additionally sets up TypeScript programs that can be used by typed rules.
Many projects today start with ESLint configs that look something like:
module.exports = {
parserOptions: {
project: './tsconfig.json',
tsconfigRootDir: __dirname,
},
};
In larger repos, parserOptions.project
often ends up being one of the three traditionally allowed forms:
project: './tsconfig.json'
project: './packages/**/tsconfig.json'
project: ['./packages/**/tsconfig.json', './separate-package/tsconfig.json']
Explicitly indicating which TSConfig files are used for typed linting can be useful. Developers like being given explicit control over their tooling. However, we've seen a few issues arise from this approach:
Although developers may sometimes need exact control over their parserOptions.project
, most of the time we just want to use the nearest tsconfig.json
to each linted file, which is the TSConfig used by the editor by default.
In other words, many developers want our issue #101: Feature request: support looking up tsconfig.json relative to linted file.
Introducingtrue
As of typescript-eslint 5.52.0, we now support providing true
for parserOptions.project
:
module.exports = {
parserOptions: {
project: true,
tsconfigRootDir: __dirname,
},
};
Doing so indicates that each source file being linted should use type information based on the nearest tsconfig.json
in its directory. For each file, @typescript-eslint/parser
will check that file's directory, then the parent directory, and so on - until a tsconfig.json
file is found.
tip
We recommend setting the tsconfigRootDir
ESLint config to the project's root directory (most commonly, __dirname
). That way, if you accidentally delete or rename the root tsconfig.json
file, @typescript-eslint/parser
won't search parent directories for higher tsconfig.json
files.
true
If your project uses typed linting and manually specifies tsconfig.json
files, we'd highly recommend trying out parserOptions.project: true
. We've seen it reduce lines of code in ESLint configurations in many early adopters. Sometimes, it even reduces time spent on typed linting by helping projects use a simpler set of TSConfigs. 🚀
In the long term, we're hoping to further improve the configuration and performance for typed linting (see Project Services below). Simplifying your configuration now will make it easier to onboard to our new options when they're available.
How It WorksWhen @typescript-eslint/parser
is configured to generate type information, it attaches a backing TypeScript "Program" for each file it parses. Those Programs provide type checking APIs used by lint rules. Each TSConfig file on disk is generally used to create exactly one Program, and files included by the same TSConfig file will reuse the same Program.
Depending on how the ESLint config's parserOptions.project
was specified, determining which TSConfig file to use for each file can be different:
"tsconfig.json"
), only one Program will be created, and all linted files will reuse it."./packages/*/tsconfig.json"
), each linted file will use the Program created by the first matched TSConfig file.For true
, each linted file will first try the tsconfig.json
in its directory, then its parent directory, and so on until one is found on disk or the directory root (parserOptions.tsconfigRootDir
) is reached.
note
@typescript-eslint/parser
caches those directory tsconfig.json
file lookups for a duration corresponding to parserOptions.cacheLifetime
. No potential TSConfig path should be checked more than once in a lint run.
See feat(typescript-estree): allow specifying project: true for the backing code changes.
What's Next Investigating Custom TSConfig NamesSome projects use TSConfig files with names other than tsconfig.json
: most commonly, tsconfig.eslint.json
. parserOptions.project: true
does not support specifying different name(s) to search for. We have two followup issues filed to investigate fleshing out that support:
If either of those two issues would benefit you, please 👍 react to them. And if your project has a use case not yet mentioned in their comments, please post that use case. We want to know what's important for users!
Project ServicesThe downside of having users specify parserOptions.project
at all is that @typescript-eslint/parser
needs manual logic to create TypeScript Programs and associate them with linted files. Manual Program creation logic comes with a few issues:
.eslintrc.(c)js
files can be tricky to lint, resulting in the dreaded TSConfig does not include this file error.We're working on an option to instead call the same TypeScript "Project Service" APIs that editors such as VS Code use to create Programs for us instead. Project Services will automatically detect the TSConfig for each file (like project: true
), and will also allow type information to be computed for JavaScript files without the allowJs
compiler option (unlike project: true
).
We hope this option will eventually become the standard way to enable typed linting. However, because it's so new and untested, we're keeping it under the EXPERIMENTAL_
prefix for at least all of the 6.X
versions.
See Packages > Parser > EXPERIMENTAL_useProjectService
for more information.
If you enjoyed this blog post and/or use typescript-eslint, please consider supporting us on Open Collective. We're a small volunteer team and could use your support to make the ESLint experience on TypeScript great. Thanks! 💖
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4