Newer Information Available
This blog post is now out of date, as we've released typescript-eslint v6! π Please see Announcing typescript-eslint v6 for the latest information.
typescript-eslint is the tooling that enables standard JavaScript tools such as ESLint and Prettier to support TypeScript code. We've been working on a set of breaking changes and general features that we're excited to get in front of users soon. And now, after over two years of development, we're excited to say that typescript-eslint v6 is ready for public beta testing! π
Our plan for typescript-eslint v6 is to:
Nothing mentioned in this blog post is set in stone. If you feel passionately about any of the choices we've made here -positively or negatively- then do let us know on the typescript-eslint Discord's #v6
channel!
Please do try out the typescript-eslint v6 beta!
As A New UserβIf you don't yet use typescript-eslint, you can go through our configuration steps on the v6 Getting Started docs. It'll walk you through setting up typescript-eslint in a project.
To use v6 specifically, see the following section for an updated install command.
As An Existing UserβIf you already use typescript-eslint, you'll need to first replace your package's previous versions of @typescript-eslint/eslint-plugin
and @typescript-eslint/parser
with @rc-v6
versions:
npm i @typescript-eslint/eslint-plugin@rc-v6 @typescript-eslint/parser@rc-v6 --save-dev
We highly recommend then basing your ESLint configuration on the reworked typescript-eslint recommended configurations mentioned later in this post β especially if it's been a while since you've reworked your linter config.
User-Facing Breaking ChangesβThese are the changes that users of typescript-eslint -generally, any developer running ESLint on TypeScript code- should pay attention to when upgrading typescript-eslint from v5 to v6.
Reworked Configuration Namesββ³ indicates a change that has been scheduled for v6 but not yet released. We'll update this blog post as the corresponding pull requests land.
The biggest configuration change in typescript-eslint v6 is that we've reworked the names of our provided user configuration files. typescript-eslint v5 provided three recommended configurations:
recommended
: Recommended rules for code correctness that you can drop in without additional configuration.recommended-requiring-type-checking
: Additional recommended rules that require type information.strict
: Additional strict rules that can also catch bugs but are more opinionated than recommended rules.Those configurations worked well for most projects. However, some users correctly noted two flaws in that approach:
As a result, we've reworked the configurations provided by typescript-eslint into these two groups:
recommended
: Recommended rules that you can drop in without additional configuration.recommended-type-checked
: Additional recommended rules that require type information.strict
: Additional strict rules that can also catch bugs but are more opinionated than recommended rules (without type information).strict-type-checked
: Additional strict rules that do require type information.stylistic
: Stylistic rules you can drop in without additional configuration.stylistic-type-checked
: Additional stylistic rules that require type information.
recommended-requiring-type-checking
is now an alias forrecommended-type-checked
. The alias will be removed in a future major version.
As of v6, we recommend that projects enable two configs from the above:
stylistic
and either recommended
or strict
, depending on how intensely you'd like your lint rules to scrutinize your code.stylistic-type-checked
and either recommended-type-checked
or strict-type-checked
, depending on how intensely you'd like your lint rules to scrutinize your code.For example, a typical project that enables typed linting might have an ESLint configuration file that changes like:
.eslintrc.cjs
module.exports = {
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
'plugin:@typescript-eslint/recommended-requiring-type-checking',
'plugin:@typescript-eslint/recommended-type-checked',
'plugin:@typescript-eslint/stylistic-type-checked',
],
plugins: ['@typescript-eslint'],
parser: '@typescript-eslint/parser',
parserOptions: {
project: './tsconfig.json',
project: true,
tsconfigRootDir: __dirname,
},
root: true,
};
See Configurations on the v6 docs site preview for the updated documentation on configurations provided by typescript-eslint.
For more information on these changes, see:
Every new major version of typescript-eslint comes with changes to which rules are enabled in the preset configurations - and with which options. Because this release also includes a reworking of the configurations themselves, the list of changes is too large to put in this blog post. Instead see the table in Changes to configurations for 6.0.0 for a full list of the changes.
Please do try out the new rule configurations presets and let us know in that discussion!
tip
If your ESLint configuration contains many rules
configurations, we suggest the following strategy to start anew:
eslint-disable
comments, turn off any rules creating too many errors for you to fix - with "TODO" comments linking to tracking issues/tickets to re-enable themMiscellaneous changes to all shared configurations include:
valid-typeof
rule from our preset configs.Several rules were changed in significant enough ways to be considered breaking changes:
@typescript-eslint/no-duplicate-imports
@typescript-eslint/no-implicit-any-catch
@typescript-eslint/no-parameter-properties
@typescript-eslint/sort-type-union-intersection-members
@typescript-eslint/prefer-nullish-coalescing
rule to also check ||=
expressions.@typescript-eslint/prefer-optional-chain
rule to fix numerous false positives, at the cost of making it require type information.createDefaultProgram
to deprecated__createDefaultProgram
, with associated @deprecated
TSDoc tags and warnings.isTypeReadonlyArrayOrTuple
function's first argument from a checker: ts.TypeChecker
to a full program: ts.Program
typescript-eslint v6 comes with a suite of cleanups and improvements for developers as well. If you author any ESLint plugins or other tools that interact with TypeScript syntax, then we recommend you try out typescript-eslint v6 soon. It includes some breaking changes that you may need to accommodate for.
Type Checker Wrapper APIsβAs described in our ASTs and typescript-eslint post, ESLint rules don't natively work with AST nodes compatible with TypeScript's API. Retrieving type information for an ESLint AST node in a custom rule requires code somewhat like:
custom-rule-with-v5.ts
{
create() {
const services = util.getParserServices(context);
const checker = services.program.getTypeChecker();
const tsNode = services.esTreeNodeToTSNodeMap.get(esNode);
const type = checker.getTypeAtLocation(node);
}
}
How cumbersome, just to call to a single method (getTypeAtLocation
) on the TypeScript API!
In typescript-eslint v6, we've added a set of wrapper APIs on the services: ParserServices
object that act as shortcuts for commonly used TypeScript APIs including getTypeAtLocation
:
custom-rule-with-v6.ts
{
create() {
const services = util.getParserServices(context);
const type = services.getTypeAtLocation(node);
}
}
For now, the available wrapper APIs are:
getSymbolAtLocation
: passes an ESTree's equivalent TypeScript node to checker.getSymbolAtLocation
getTypeAtLocation
: passes an ESTree node's equivalent TypeScript node to checker.getTypeAtLocation
We hope these wrapper APIs make it more convenient to write lint rules that rely on the awesome power of TypeScript's type checking. In the future, we may add more wrapper APIs, and may even add internal caching to those APIs to improve performance.
Newer Information Available
Rules can still retrieve their full backing TypeScript type checker with services.program.getTypeChecker()
. This can be necessary for TypeScript APIs not wrapped by the parser services.
See Custom Rules on the v6 docs site preview for the updated documentation on creating custom rules with typescript-eslint.
AST Breaking ChangesβThese PRs changed the AST shapes generated by typescript-eslint when parsing code. If you author any ESLint rules that refer to the syntax mentioned by them, these are relevant to you.
node.parent
property on AST nodes non-optional (TSESTree.Node
instead of TSESTree.Node | undefined
).ArrayExpressions
's elements
property can now include null
(i.e. is now (Expression | SpreadElement | null)[]
), for the case of sparse arrays (e.g. [1, , 3]
).MemberExpression
's object
property is now Expression
, not LeftHandSideExpression
.ObjectLiteralElement
no longer allows for MethodDefinition
.TSImportEqualsDeclaration
nodes are now wrapped in an ExportNamedDeclaration
node instead of having .isExport = true
property.MethodDefinitionBase
no longer has a typeParameters
property.TSIndexSignature
, TSMethodSignature
, and TSPropertySignatureBase
no longer have an export
property.TSPropertySignatureBase
no longer has an initializer
property.Abc.Def
now use a TSQualifiedName
node, instead of a nested body structure.Newer Information Available
These changes only impact API consumers of typescript-eslint that work at parsing level. If the extent of your API usage is writing custom rules, these changes don't impact you.
The @typescript-eslint/typescript-estree
parser is by default very forgiving of invalid ASTs. If it encounters invalid syntax, it will still attempt create an AST if possible: even if required properties of nodes don't exist.
For example, this snippet of TypeScript code creates a ClassDeclaration
whose id
is null
:
Invalid parsed ASTs can cause problems for downstream tools expecting AST nodes to adhere to the ESTree spec. ESLint rules in particular tend to crash when given invalid ASTs.
@typescript-eslint/typescript-estree
will now throw an error when it encounters a known invalid AST such as the export class {}
example. This is generally the correct behavior for most parsing contexts so downstream tools don't have to work with a potentially invalid AST.
For consumers that don't want the updated behavior of throwing on invalid ASTs, a new allowInvalidAST
option exists to disable the throwing behavior. Keep in mind that with it enabled, ASTs produced by typescript-eslint might not match their TSESTree type definitions.
For more information, see:
RuleTester
packageβ
Previously we provided a version of ESLint's RuleTester
class from @typescript-eslint/utils/eslint-utils
. This version was a sub-class of the original version and was implemented in a very fragile way that made it hard to test, maintain and build new features into.
This was also reasonably cumbersome for users to access as users had to do deep imports in order to access the class without a namespace.
In v6 we have extracted this into its own package - @typescript-eslint/rule-tester
. Additionally instead of being a hacky subclass it's now a complete fork of the original tooling. For the most part you should be able to update your tests as follows:
import { TSESLint } from '@typescript-eslint/utils';
import { RuleTester } from '@typescript-eslint/rule-tester';
import rule from '../src/rules/my-rule';
const ruleTester = new TSESLint.RuleTester({
const ruleTester = new RuleTester({
parser: '@typescript-eslint/parser',
});
ruleTester.run('my-rule', rule, { });
Breaking changes:
parserOptions.ecmaFeatures.jsx = true
the rule tester would attempt to look for a fixture named file.tsx
. Now instead the rule tester will look for a file named react.tsx
.
file.ts
and file.tsx
and TypeScript would ignore one of those files, causing weird breakages in tests.defaultFilenames
to the RuleTester
constructor.New features:
skip: boolean
- the inverse option of only: boolean
. When true
we will use your test framework's test skip functionality (it.skip
) to mark the test as skipped. This is useful during development as it enables you to control which tests run without needing to comment blocks out.For more information on the package, see the rule-tester
package documentation.
createRule
-created rules more portable in the type system.TSESLintScope
types from the @typescript-eslint/utils
package. Use @typescript-eslint/scope-manager
directly instead.console.log
that triggers only in test environments, to encourage developers to move off of them.@typescript-eslint/scope-manager
no longer includes properties referring to ecmaVersion
, isES6
, or other ECMA versioning options. It instead now always assumes ESNext.parserOptions.project
, parser services will no longer include a program
with incomplete type information. program
will be null
instead.
errorOnTypeScriptSyntacticAndSemanticIssues
option will no longer be allowed if parserOptions.project
is not provided.@typescript-eslint/experimental-utils
package has since been renamed to @typescript-eslint/utils
.?: boolean
to : boolean
, as well as some properties marked as ?:
optional to | undefined
. This results in more predictable AST node object shapes.visitorKeys
can now only be imported from @typescript-eslint/visitor-keys
. Previously it was also re-exported by @typescript-eslint/utils
.@typescript-eslint/*
packages now use exports
to prevent importing internal file paths.@typescript-eslint/utils
now exports a more strict version of JSONSchema4
types, which are more strict in type checking rule options typesWe'd like to extend a sincere thank you to everybody who pitched in to make typescript-eslint v6 possible.
See the v6.0.0 milestone for the list of issues and associated merged pull requests.
Supporting typescript-eslintβ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