<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>typescript-eslint Blog</title>
        <link>https://typescript-eslint.io/blog</link>
        <description>typescript-eslint Blog</description>
        <lastBuildDate>Mon, 05 Jan 2026 00:00:00 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>en</language>
        <item>
            <title><![CDATA[Revamping the `ban-types` rule]]></title>
            <link>https://typescript-eslint.io/blog/revamping-the-ban-types-rule</link>
            <guid>https://typescript-eslint.io/blog/revamping-the-ban-types-rule</guid>
            <pubDate>Mon, 05 Jan 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[How the now-deprecated `ban-types` rule evolved over time to what is now several newer, targeted rules.]]></description>
            <content:encoded><![CDATA[<p>For many years, <code>@typescript-eslint/ban-types</code> was one of the more prominent rules in typescript-eslint.
It served three purposes:</p>
<ul>
<li>It banned usage of the unsafe "empty object" <code>{}</code> type</li>
<li>It banned uses of dangerous or misleading built-in types: <code>Function</code>, <code>Number</code>, and so on</li>
<li>It also allowed users to provide additional types to ban</li>
</ul>
<p>Those are all great areas for linting!
However, <code>@typescript-eslint/ban-types</code> suffered from several key design issues:</p>
<ul>
<li>By targeting all three areas of banning, it was hard to configure to only what a project needs</li>
<li>It was overly strict on banning <code>{}</code>, to the point of confusing and inconveniencing users</li>
<li>It was limited in what auto-fixes and edge cases it could handle for its default banned types</li>
</ul>
<p>This post will explain how <code>@typescript-eslint/ban-types</code> came to be, its benefits and drawbacks, and the new rules that better handle its targeted functionality.</p>
<h2 class="anchor anchorWithStickyNavbar_eAos" id="a-brief-history-of-ban-types">A Brief History of <code>ban-types</code><a href="https://typescript-eslint.io/blog/revamping-the-ban-types-rule#a-brief-history-of-ban-types" class="hash-link" aria-label="Direct link to a-brief-history-of-ban-types" title="Direct link to a-brief-history-of-ban-types">​</a></h2>
<p>The first version of a <em>"ban types"</em> lint rule came from <a href="https://palantir.github.io/tslint" target="_blank" rel="noopener noreferrer">TSLint</a>, a now-deprecated TypeScript-only linter predating typescript-eslint.
<a href="http://palantir.github.io/tslint/rules/ban-types" target="_blank" rel="noopener noreferrer">TSLint's <code>ban-type</code> rule</a> didn't ban any types by default.
It would only ban types explicitly declared in a project's linting config.</p>
<p>When the rule was ported to <code>@typescript-eslint/ban-types</code>, it was changed to additionally lint against known dangerous built-in types by default.
Doing so meant that the <code>plugin:typescript-eslint/recommended</code> preset config would lint against them by default.</p>
<p>The drawback of linting against those types by default was that nuanced types such as <code>object</code> and <code>{}</code> went through the same limited configuration channels as more straightforward types like <code>Function</code>.
<code>{}</code> in particular has nuance of when it should be used -- which is not describable in a rule configuration format.</p>
<p>As of typescript-eslint v8, the old <code>@typescript-eslint/ban-types</code> rule has now been split into several more targeted rules.
Those rules each capture one of the targeted areas of the now-deprecated <code>@ytpescript-eslint/ban-types</code> rule.
By splitting into several rules, each has more specific, user-friendly configuration options and documentation pages.</p>
<h2 class="anchor anchorWithStickyNavbar_eAos" id="empty-object-types">Empty Object Types<a href="https://typescript-eslint.io/blog/revamping-the-ban-types-rule#empty-object-types" class="hash-link" aria-label="Direct link to Empty Object Types" title="Direct link to Empty Object Types">​</a></h2>
<p><a href="https://typescript-eslint.io/rules/no-empty-object-type"><code>@typescript-eslint/no-empty-object-type</code></a> is the new rule for banning the built-in <code>{}</code> type in confusing locations.
The <code>{}</code>, or "empty object" type in TypeScript is a common source of confusion for developers unfamiliar with TypeScript's structural typing.
These developers think <code>{}</code> represents "an object with no properties", however <code>{}</code> represents any <em>non-nullish value</em>. This means that it can represent any object with 0 or more properties or even primitives like strings, numbers, and booleans:</p>
<div class="language-ts codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockContent_m3Ux"><pre class="prism-code language-ts codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line"><span class="token keyword">let</span><span class="token plain"> anyNonNullishValue</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token plain"> </span><span class="token operator">=</span><span class="token plain"> </span><span class="token string">'Intentionally allowed by TypeScript.'</span><span class="token punctuation">;</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Often, developers writing <code>{}</code> actually mean either:</p>
<ul>
<li><code>object</code>: representing any <em>object</em> value</li>
<li><code>unknown</code>: representing any value at all, including <code>null</code> and <code>undefined</code></li>
</ul>
<p>In other words, the "empty object" type <code>{}</code> really means <em>"any value that is defined"</em>.
That includes arrays, class instances, functions, and primitives such as <code>string</code> and <code>symbol</code>.
The word "object" in its name is a bit of a misnomer.</p>
<p><code>{}</code> empty objects are permissible in a few edge cases, most commonly:</p>
<ul>
<li>Intersection constituents (e.g. types like TypeScript's <code>type NonNullable&lt;T&gt; = T &amp; {}</code>)</li>
<li>Interfaces that extend from multiple other interfaces and add no fields of their own</li>
</ul>
<p>Those cases could not be described with the old <code>@typescript-eslint/ban-types</code> format.
Now, they are encoded as exemptions in the new <a href="https://typescript-eslint.io/rules/no-empty-object-type"><code>@typescript-eslint/no-empty-object-type</code></a> rule.</p>
<h2 class="anchor anchorWithStickyNavbar_eAos" id="function-types"><code>Function</code> Types<a href="https://typescript-eslint.io/blog/revamping-the-ban-types-rule#function-types" class="hash-link" aria-label="Direct link to function-types" title="Direct link to function-types">​</a></h2>
<p><a href="https://typescript-eslint.io/rules/no-unsafe-function-type"><code>@typescript-eslint/no-unsafe-function-type</code></a> is the new rule for banning the built-in <code>Function</code> type.
The built-in <code>Function</code> type is an overly permissive way to describe a function.
It allows being called with any number of arguments and returns type <code>any</code>.</p>
<div class="language-ts codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockContent_m3Ux"><pre class="prism-code language-ts codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line"><span class="token keyword">const</span><span class="token plain"> anyFunction</span><span class="token operator">:</span><span class="token plain"> </span><span class="token function-variable function">Function</span><span class="token plain"> </span><span class="token operator">=</span><span class="token plain"> </span><span class="token punctuation">(</span><span class="token plain">arg</span><span class="token operator">:</span><span class="token plain"> </span><span class="token builtin">boolean</span><span class="token punctuation">)</span><span class="token plain"> </span><span class="token operator">=&gt;</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token function">anyFunction</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token plain"> </span><span class="token comment">// Ok</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token function">anyFunction</span><span class="token punctuation">(</span><span class="token number">123</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token plain"> </span><span class="token comment">// Ok</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token function">anyFunction</span><span class="token punctuation">(</span><span class="token string">'abc'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token plain"> </span><span class="token comment">// Ok</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token keyword">const</span><span class="token plain"> numberValue</span><span class="token operator">:</span><span class="token plain"> </span><span class="token builtin">number</span><span class="token plain"> </span><span class="token operator">=</span><span class="token plain"> </span><span class="token function">anyFunction</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token plain"> </span><span class="token comment">// Ok</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token keyword">const</span><span class="token plain"> stringValue</span><span class="token operator">:</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token plain"> </span><span class="token operator">=</span><span class="token plain"> </span><span class="token function">anyFunction</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token plain"> </span><span class="token comment">// Ok</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Instead of using <code>Function</code>, code should generally specify function parameters and return types in types.
Common cases and more examples are noted in the new <a href="https://typescript-eslint.io/rules/no-unsafe-function-type"><code>@typescript-eslint/no-unsafe-function-type</code></a> rule's documentation.</p>
<h2 class="anchor anchorWithStickyNavbar_eAos" id="primitive-wrapper-types">Primitive Wrapper Types<a href="https://typescript-eslint.io/blog/revamping-the-ban-types-rule#primitive-wrapper-types" class="hash-link" aria-label="Direct link to Primitive Wrapper Types" title="Direct link to Primitive Wrapper Types">​</a></h2>
<p><a href="https://typescript-eslint.io/rules/no-wrapper-object-types"><code>@typescript-eslint/no-wrapper-object-types</code></a> is the new rule for banning <code>Object</code> and built-in class wrappers such as <code>Boolean</code> and <code>Number</code>.
TypeScript defines uppercase "wrapper" object types corresponding to each of JavaScript's primitive data types and equivalent wrapper classes: <code>boolean</code>/<code>Boolean</code>, <code>number</code>/<code>Number</code>, and so on.</p>
<div class="language-ts codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockContent_m3Ux"><pre class="prism-code language-ts codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line"><span class="token keyword">let</span><span class="token plain"> myNumber</span><span class="token operator">:</span><span class="token plain"> Number</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line"><span class="token plain">myNumber </span><span class="token operator">=</span><span class="token plain"> </span><span class="token number">0</span><span class="token punctuation">;</span><span class="token plain"> </span><span class="token comment">// Ok</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">myNumber </span><span class="token operator">=</span><span class="token plain"> </span><span class="token function">Number</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token plain"> </span><span class="token comment">// Ok</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token keyword">let</span><span class="token plain"> myObject</span><span class="token operator">:</span><span class="token plain"> Object </span><span class="token operator">=</span><span class="token plain"> </span><span class="token string">'allowed by TypeScript'</span><span class="token punctuation">;</span><span class="token plain"> </span><span class="token comment">// Ok</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Due to the quirks of TypeScript's structural typing, the corresponding primitives are also assignable to these uppercase types, since they have the same "shape".
Instances of the uppercase class types also have surprisingly different behaviors at runtime, including always being truthy (even for values like <code>new Boolean(false)</code>) and being compared by reference (<code>new String("a") !== new String("a")</code>).</p>
<p>Instead of using uppercase wrapper object types, code should generally stick with lower-case primitive types.
Common cases and more examples are noted in the new <a href="https://typescript-eslint.io/rules/no-wrapper-object-types"><code>@typescript-eslint/no-wrapper-object-types</code></a> rule's documentation.</p>
<h2 class="anchor anchorWithStickyNavbar_eAos" id="user-defined-type-bans">User-Defined Type Bans<a href="https://typescript-eslint.io/blog/revamping-the-ban-types-rule#user-defined-type-bans" class="hash-link" aria-label="Direct link to User-Defined Type Bans" title="Direct link to User-Defined Type Bans">​</a></h2>
<p><a href="https://typescript-eslint.io/rules/no-restricted-types"><code>@typescript-eslint/no-restricted-types</code></a> is the new rule for banning a configurable list of type names.
It acts similarly to the old <code>ban-types</code> rule:</p>
<ul>
<li>It defines no types by default: i.e. it must be configured to be useful</li>
<li>It allows specifying types to ban, along with optional messages to display</li>
</ul>
<p>As with <code>@typescript-eslint/ban-types</code>, <code>@typescript-eslint/no-restricted-types</code> additionally allows specifying auto-fixes to replace types with.
The new rule also allows specifying suggestions to surface in editors, for cases when the fix isn't known to be reliable.</p>
<p>Here's an example of configuring the new rule to ban a deprecated API, with a custom message and two suggestions:</p>
<div class="language-ts codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockContent_m3Ux"><pre class="prism-code language-ts codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line"><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">"@typescript-eslint/no-restricted-types"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation">[</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">    </span><span class="token string">"error"</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">    </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">      </span><span class="token string-property property">"types"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">        </span><span class="token string-property property">"DeprecatedOldAPI"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">          </span><span class="token string-property property">"message"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">"Use either NewAPIOne or NewAPITwo instead"</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">          </span><span class="token string-property property">"suggest"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation">[</span><span class="token string">"NewAPIOne"</span><span class="token punctuation">,</span><span class="token plain"> </span><span class="token string">"NewAPITwo"</span><span class="token punctuation">]</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">        </span><span class="token punctuation">}</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">      </span><span class="token punctuation">}</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">    </span><span class="token punctuation">}</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token punctuation">]</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token punctuation">}</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>By acting as a purely user-configured rule, <code>@typescript-eslint/no-restricted-types</code>'s behavior falls in line with core ESLint rules like <a href="https://eslint.org/docs/latest/no-restricted-imports" target="_blank" rel="noopener noreferrer"><code>no-restricted-imports</code></a> and <a href="https://eslint.org/docs/latest/no-restricted-syntax" target="_blank" rel="noopener noreferrer"><code>no-restricted-syntax</code></a>.</p>
<p>See the new <a href="https://typescript-eslint.io/rules/no-restricted-types"><code>@typescript-eslint/no-restricted-types</code></a> rule's documentation for more information on how to configure it.</p>
<h2 class="anchor anchorWithStickyNavbar_eAos" id="closing-thoughts">Closing Thoughts<a href="https://typescript-eslint.io/blog/revamping-the-ban-types-rule#closing-thoughts" class="hash-link" aria-label="Direct link to Closing Thoughts" title="Direct link to Closing Thoughts">​</a></h2>
<p>We'd like to give a big thanks to all the users who gave feedback on the old <code>@typescript-eslint/ban-types</code> rule.
In particular, we'd like to thank <a href="https://github.com/RyanCavanaugh" target="_blank" rel="noopener noreferrer">Ryan Cavanaugh</a> from the TypeScript team for advising on the rule's design (and for dealing with users frequently sending issues to TypeScript itself on what was actually an overly aggressive lint rule).</p>
<h2 class="anchor anchorWithStickyNavbar_eAos" id="supporting-typescript-eslint">Supporting typescript-eslint<a href="https://typescript-eslint.io/blog/revamping-the-ban-types-rule#supporting-typescript-eslint" class="hash-link" aria-label="Direct link to Supporting typescript-eslint" title="Direct link to Supporting typescript-eslint">​</a></h2>
<p>If you enjoyed this blog post and/or use typescript-eslint, please consider <a href="https://opencollective.com/typescript-eslint" target="_blank" rel="noopener noreferrer">supporting us on Open Collective</a>. We're a small volunteer team and could use your support to make the ESLint experience on TypeScript great. Thanks! 💖</p>]]></content:encoded>
            <category>ban-types</category>
            <category>interfaces</category>
            <category>no-empty-object-type</category>
            <category>no-restricted-types</category>
            <category>no-unsafe-function-type</category>
            <category>no-wrapper-object-types</category>
            <category>objects</category>
        </item>
        <item>
            <title><![CDATA[Typed Linting with Project Service]]></title>
            <link>https://typescript-eslint.io/blog/project-service</link>
            <guid>https://typescript-eslint.io/blog/project-service</guid>
            <pubDate>Thu, 29 May 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[How typescript-eslint's new "Project Service" makes typed linting easier to configure, especially for large projects.]]></description>
            <content:encoded><![CDATA[<p><a href="https://typescript-eslint.io/blog/typed-linting">"Typed linting"</a>, or enabling ESLint rules to understand TypeScript types, is one of the best parts of typescript-eslint.
It enables a slew of <a href="https://typescript-eslint.io/rules/?=recommended-typeInformation">more powerful lint rules</a> that check for nuanced bugs, best practice violations, and other code issues that can only be detected using type information.</p>
<p>Typed linting hasn't always been straightforward to configure or performant at runtime.
We've seen users have to manage separate <code>tsconfig.eslint.json</code> files to enable typed linting — sometimes with different compiler options than the rest of the project.
Not ideal.</p>
<p>In typescript-eslint 8.0, we stabilized a <strong><code>parserOptions.projectService</code></strong> option that uses more powerful, streamlined TypeScript APIs than before.
The "Project Service" brings several benefits:</p>
<ul>
<li>✍️ <strong>Configuration</strong>: simpler ESLint configs for typed linting with no ESLint-specific TSConfig files</li>
<li>🧠 <strong>Predictability</strong>: uses the same type information services as editors, including more reliability</li>
<li>🚀 <strong>Scalability</strong>: supporting TypeScript project references for larger repositories (i.e. monorepos)</li>
</ul>
<p>This blog post will cover how <code>parserOptions.projectService</code> simplifies configurations and aligns linting type information to what editors such as VS Code run with.</p>
<div class="theme-admonition theme-admonition-tip admonition_pzuZ alert alert--success"><div class="admonitionHeading_uJho"><span class="admonitionIcon_vMH2"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>tip</div><div class="admonitionContent_gazR"><p>See <a href="https://typescript-eslint.io/getting-started">Getting Started</a> to learn how to lint JavaScript and TypeScript code with typescript-eslint, then <a href="https://typescript-eslint.io/getting-started/typed-linting">Linting with Type Information</a> to onboard to typed linting.</p></div></div>
<h2 class="anchor anchorWithStickyNavbar_eAos" id="introducing-the-project-service">Introducing the Project Service<a href="https://typescript-eslint.io/blog/project-service#introducing-the-project-service" class="hash-link" aria-label="Direct link to Introducing the Project Service" title="Direct link to Introducing the Project Service">​</a></h2>
<p>Back in <a href="https://typescript-eslint.io/blog/parser-options-project-true#project-services">Relative TSConfig Projects with <code>parserOptions.project = true</code> &gt; Project Services</a>, we'd mentioned a replacement for <code>parserOptions.project</code>:</p>
<blockquote>
<p>The downside of having users specify <code>parserOptions.project</code> at all is that <code>@typescript-eslint/parser</code> needs manual logic to create TypeScript Programs and associate them with linted files.
Manual Program creation logic comes with a few issues: ...</p>
<p>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 <code>project: true</code>), and will also allow type information to be computed for JavaScript files without the <code>allowJs</code> compiler option (unlike <code>project: true</code>).</p>
</blockquote>
<p>Following a year of discussion and beta testing in typescript-eslint v6 and v7, we believe the new Project Service API is ready to be used by real-world projects.
We therefore promoted the <code>parserOptions.EXPERIMENTAL_useProjectService</code> option to the stable name <strong><code>parserOptions.projectService</code></strong> in typescript-eslint v8.</p>
<div class="theme-admonition theme-admonition-note admonition_pzuZ alert alert--secondary"><div class="admonitionHeading_uJho"><span class="admonitionIcon_vMH2"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>note</div><div class="admonitionContent_gazR"><p>See <a href="https://typescript-eslint.io/blog/announcing-typescript-eslint-v8#project-service">Announcing typescript-eslint v8 &gt; Project Service</a> for the original announcement.</p></div></div>
<h2 class="anchor anchorWithStickyNavbar_eAos" id="configuration">Configuration<a href="https://typescript-eslint.io/blog/project-service#configuration" class="hash-link" aria-label="Direct link to Configuration" title="Direct link to Configuration">​</a></h2>
<p>You can change over to the new Project Service API by replacing <code>project</code> with <code>projectService</code> in your ESLint configuration:</p>
<div class="tabs-container tabList_hoTN"><ul role="tablist" aria-orientation="horizontal" class="tabs"><li role="tab" tabindex="0" aria-selected="true" class="tabs__item tabItem_dW3K tabs__item--active">Flat Config</li><li role="tab" tabindex="-1" aria-selected="false" class="tabs__item tabItem_dW3K">Legacy Config</li></ul><div class="margin-top--md"><div role="tabpanel" class="tabItem_PzSZ"><div class="language-js codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockTitle_P25_">eslint.config.js</div><div class="codeBlockContent_m3Ux"><pre class="prism-code language-js codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line"><span class="token keyword module">export</span><span class="token plain"> </span><span class="token keyword module">default</span><span class="token plain"> tseslint</span><span class="token punctuation">.</span><span class="token method function property-access">config</span><span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token comment">// ...</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token literal-property property">languageOptions</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">    </span><span class="token literal-property property">parserOptions</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line code-block-removed-line"><span class="token plain">      </span><span class="token literal-property property">project</span><span class="token operator">:</span><span class="token plain"> </span><span class="token boolean">true</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line code-block-added-line"><span class="token plain">      </span><span class="token literal-property property">projectService</span><span class="token operator">:</span><span class="token plain"> </span><span class="token boolean">true</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">      </span><span class="token literal-property property">tsconfigRootDir</span><span class="token operator">:</span><span class="token plain"> </span><span class="token keyword module">import</span><span class="token punctuation">.</span><span class="token property-access">meta</span><span class="token punctuation">.</span><span class="token property-access">dirname</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">    </span><span class="token punctuation">}</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token punctuation">}</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token comment">// ...</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div></div><div role="tabpanel" class="tabItem_PzSZ" hidden=""><div class="language-js codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockTitle_P25_">.eslintrc.cjs</div><div class="codeBlockContent_m3Ux"><pre class="prism-code language-js codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line"><span class="token plain">module</span><span class="token punctuation">.</span><span class="token property-access">exports</span><span class="token plain"> </span><span class="token operator">=</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token comment">// ...</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token literal-property property">parser</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'@typescript-eslint/parser'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token literal-property property">parserOptions</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line code-block-removed-line"><span class="token plain">    </span><span class="token literal-property property">project</span><span class="token operator">:</span><span class="token plain"> </span><span class="token boolean">true</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line code-block-added-line"><span class="token plain">    </span><span class="token literal-property property">projectService</span><span class="token operator">:</span><span class="token plain"> </span><span class="token boolean">true</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">    </span><span class="token literal-property property">tsconfigRootDir</span><span class="token operator">:</span><span class="token plain"> __dirname</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token punctuation">}</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token comment">// ...</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token punctuation">}</span><span class="token punctuation">;</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div></div></div></div>
<p>That's it!</p>
<p>Other settings, including how you run ESLint and configure rules, should work the same.</p>
<div class="theme-admonition theme-admonition-tip admonition_pzuZ alert alert--success"><div class="admonitionHeading_uJho"><span class="admonitionIcon_vMH2"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>tip</div><div class="admonitionContent_gazR"><p>See <a href="https://typescript-eslint.io/packages/parser#projectservice">Packages &gt; Parser &gt; <code>projectService</code></a> for more details on granular configuration options.</p></div></div>
<h3 class="anchor anchorWithStickyNavbar_eAos" id="additional-files">Additional Files<a href="https://typescript-eslint.io/blog/project-service#additional-files" class="hash-link" aria-label="Direct link to Additional Files" title="Direct link to Additional Files">​</a></h3>
<p>One long-standing pain point of typed linting was enabling typed linting for files not included in the project's <code>tsconfig.json</code>.
Common solutions in the traditional Program API were to either skip typed linting for those files or to create a <code>tsconfig.eslint.json</code> enabling the <code>allowJs</code> compiler option.</p>
<p>The new Project Service API allows for a configuration object specifying <code>allowDefaultProject</code>: a glob of "out-of-project" files to lint with type information.
That means you can lint those files without any new configuration files or TypeScript compiler options!</p>
<p>For example, the following config solves the common case of projects that have root-level files like <code>eslint.config.js</code> or <code>vitest.config.ts</code>:</p>
<div class="tabs-container tabList_hoTN"><ul role="tablist" aria-orientation="horizontal" class="tabs"><li role="tab" tabindex="0" aria-selected="true" class="tabs__item tabItem_dW3K tabs__item--active">Flat Config</li><li role="tab" tabindex="-1" aria-selected="false" class="tabs__item tabItem_dW3K">Legacy Config</li></ul><div class="margin-top--md"><div role="tabpanel" class="tabItem_PzSZ"><div class="language-js codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockTitle_P25_">eslint.config.js</div><div class="codeBlockContent_m3Ux"><pre class="prism-code language-js codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line"><span class="token keyword module">export</span><span class="token plain"> </span><span class="token keyword module">default</span><span class="token plain"> tseslint</span><span class="token punctuation">.</span><span class="token method function property-access">config</span><span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token comment">// ...</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token literal-property property">languageOptions</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">    </span><span class="token literal-property property">parserOptions</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">      </span><span class="token literal-property property">projectService</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">        </span><span class="token literal-property property">allowDefaultProject</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation">[</span><span class="token string">'*.js'</span><span class="token punctuation">]</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">      </span><span class="token punctuation">}</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">      </span><span class="token literal-property property">tsconfigRootDir</span><span class="token operator">:</span><span class="token plain"> </span><span class="token keyword module">import</span><span class="token punctuation">.</span><span class="token property-access">meta</span><span class="token punctuation">.</span><span class="token property-access">dirname</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">    </span><span class="token punctuation">}</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token punctuation">}</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token comment">// ...</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div></div><div role="tabpanel" class="tabItem_PzSZ" hidden=""><div class="language-js codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockTitle_P25_">.eslintrc.cjs</div><div class="codeBlockContent_m3Ux"><pre class="prism-code language-js codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line"><span class="token plain">module</span><span class="token punctuation">.</span><span class="token property-access">exports</span><span class="token plain"> </span><span class="token operator">=</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token comment">// ...</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token literal-property property">parser</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'@typescript-eslint/parser'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token literal-property property">parserOptions</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">    </span><span class="token literal-property property">projectService</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">      </span><span class="token literal-property property">allowDefaultProject</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation">[</span><span class="token string">'*.js'</span><span class="token punctuation">]</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">      </span><span class="token literal-property property">tsconfigRootDir</span><span class="token operator">:</span><span class="token plain"> __dirname</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">    </span><span class="token punctuation">}</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token punctuation">}</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token comment">// ...</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token punctuation">}</span><span class="token punctuation">;</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div></div></div></div>
<p>This means most projects should be able to remove all <code>tsconfig.eslint.json</code> files!
🥳</p>
<div class="theme-admonition theme-admonition-tip admonition_pzuZ alert alert--success"><div class="admonitionHeading_uJho"><span class="admonitionIcon_vMH2"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>tip</div><div class="admonitionContent_gazR"><p>See <a href="https://typescript-eslint.io/packages/parser#projectserviceoptions">Packages &gt; Parser &gt; <code>projectService</code> &gt; <code>ProjectServiceOptions</code></a> for more details on out-of-project files and other granular configuration options.</p></div></div>
<h2 class="anchor anchorWithStickyNavbar_eAos" id="predictability">Predictability<a href="https://typescript-eslint.io/blog/project-service#predictability" class="hash-link" aria-label="Direct link to Predictability" title="Direct link to Predictability">​</a></h2>
<p>We've found configuring <code>tsconfig.eslint.json</code> files to be a common source of confusion with the traditional Program APIs.
They can result in the type information used for <em>linting</em> accidentally being different from the type information used for <em>type checking</em>.
Unifying TypeScript configurations to the same <code>tsconfig.json</code> file(s) altogether avoids potential divergent types.</p>
<p>Another benefit of using the new Project Service API is that typed linting requires no additional work in typescript-eslint for more difficult uses of ESLint and/or TypeScript.
We sometimes had to de-optimize the traditional Program API to support use cases:</p>
<ul>
<li>CLI <code>--fix</code> mode would lose type information after the first pass (<a href="https://github.com/typescript-eslint/typescript-eslint/pull/9577" target="_blank" rel="noopener noreferrer">#9577</a>)</li>
<li>Extra file extensions such as <code>.svelte</code> and <code>.vue</code> were not supported at all (<a href="https://github.com/typescript-eslint/typescript-eslint/issues/9504" target="_blank" rel="noopener noreferrer">#9504</a>)</li>
</ul>
<p>The new Project Service API does not suffer from these issues.
It supports extra file extensions out-of-the-box and does not slow down when used with ESLint's <code>--fix</code>.</p>
<h2 class="anchor anchorWithStickyNavbar_eAos" id="scalability">Scalability<a href="https://typescript-eslint.io/blog/project-service#scalability" class="hash-link" aria-label="Direct link to Scalability" title="Direct link to Scalability">​</a></h2>
<p><a href="https://www.typescriptlang.org/docs/handbook/project-references.html" target="_blank" rel="noopener noreferrer">TypeScript's project references</a> are how many larger projects, in particular monorepos, scale TypeScript type checking.
They allow delineating discrete projects with their own <code>tsconfig.json</code> files and annotating which projects depend on which other projects.
TypeScript is able to cache type information and only recheck projects that have changed in builds based on those project references.</p>
<p>The traditional <code>parserOptions.project</code> API did not support project references for typed linting.
We had experimented with adding support, but using the manual built-in TypeScript APIs would have been a significant maintenance investment with an unclear payoff.</p>
<p>The new Project Service API does support project references out-of-the-box.
This is a huge win for monorepos, as it means you can lint all of your projects with type information without needing to create a separate <code>tsconfig.eslint.json</code> file for each project.</p>
<h2 class="anchor anchorWithStickyNavbar_eAos" id="performance">Performance<a href="https://typescript-eslint.io/blog/project-service#performance" class="hash-link" aria-label="Direct link to Performance" title="Direct link to Performance">​</a></h2>
<p>Supporting project references allows the new Project Service API to be significantly faster than the traditional <code>parserOptions.project</code> API in many monorepo cases.
We've observed improvements for typed linting speed in real-world repositories <sup><a href="https://typescript-eslint.io/blog/project-service#user-content-fn-babel-conversion-a8f2db" id="user-content-fnref-babel-conversion-a8f2db" data-footnote-ref="true" aria-describedby="footnote-label">1</a></sup> <sup><a href="https://typescript-eslint.io/blog/project-service#user-content-fn-create-t3-app-conversion-a8f2db" id="user-content-fnref-create-t3-app-conversion-a8f2db" data-footnote-ref="true" aria-describedby="footnote-label">2</a></sup> <sup><a href="https://typescript-eslint.io/blog/project-service#user-content-fn-sveltekit-conversion-a8f2db" id="user-content-fnref-sveltekit-conversion-a8f2db" data-footnote-ref="true" aria-describedby="footnote-label">3</a></sup>.
For smaller projects, the performance of the new Project Service API is similar to the traditional <code>parserOptions.project</code> API.</p>
<p>When we first started working with the new project service API, it outperformed equivalent <code>parserOptions.project</code> setups by ~10-15%.
Since then, we have observed regressions in performance that have brought it down in some cases to be slightly slower.</p>
<p>We believe the new Project Service API should be faster than the traditional API, and are treating the lack of significant improvement as a bug.
See <a href="https://github.com/typescript-eslint/typescript-eslint/issues/9571" target="_blank" rel="noopener noreferrer">⚡ Performance: parserOptions.projectService sometimes no longer outperforms parserOptions.project</a> for more information.</p>
<h2 class="anchor anchorWithStickyNavbar_eAos" id="next-steps">Next Steps<a href="https://typescript-eslint.io/blog/project-service#next-steps" class="hash-link" aria-label="Direct link to Next Steps" title="Direct link to Next Steps">​</a></h2>
<p>The new Project Service API is available in typescript-eslint v8.0.0 and later.
We've been using it in our monorepo for over a year and have been thrilled to see many community repositories adopt it as well.</p>
<h3 class="anchor anchorWithStickyNavbar_eAos" id="giving-feedback">Giving Feedback<a href="https://typescript-eslint.io/blog/project-service#giving-feedback" class="hash-link" aria-label="Direct link to Giving Feedback" title="Direct link to Giving Feedback">​</a></h3>
<p>We'd love to hear from you on how this option works for you.
Does it live up to what we've promised, and/or does it have bugs we haven't fixed yet?
Please do send us GitHub issues for any bugs you encounter or suggestions for how to improve the API.</p>
<p>The <a href="https://discord.gg/FSxKq8Tdyg" target="_blank" rel="noopener noreferrer">typescript-eslint Discord</a> is a great place to ask questions and engage with us more casually.
For support in onboarding, feel free to ask in its <code>#help</code> channel.
We'd be happy to help you try out <code>parserOptions.projectService</code> and learn more about how you use typescript-eslint.</p>
<h3 class="anchor anchorWithStickyNavbar_eAos" id="long-term-vision">Long Term Vision<a href="https://typescript-eslint.io/blog/project-service#long-term-vision" class="hash-link" aria-label="Direct link to Long Term Vision" title="Direct link to Long Term Vision">​</a></h3>
<p>The new Project Service API is a great step towards making typed linting easier and more straightforward to configure.
Our priority for the next year will be to improve the new Project Service API so that it works in all places the traditional Program API does.
We won't remove the traditional project program behavior unless and until the new Project Service API is able to fully replace it.</p>
<p>As of typescript-eslint@8.33.0, we've also extracted most of the Project Service code into a standalone <a href="https://typescript-eslint.io/packages/project-service"><code>@typescript-eslint/project-service</code></a> package.
It has no dependencies on ESLint and is designed to be usable for any linter to enable TypeScript's Project Service API for typed linting.
See <a href="https://typescript-eslint.io/packages/project-service">Packages &gt; Project Service</a> for more details.</p>
<p>We're also looking forward to investigating support for <a href="https://github.com/typescript-eslint/typescript-eslint/issues/10940" target="_blank" rel="noopener noreferrer">TypeScript's 10x faster Go port</a>.
Abstracting configuration details into the Project Service API means it will be much easier for typescript-eslint to support typed linting using "tsgo" without any additional user configuration.</p>
<p>So, please, try out the new Project Service API.
We're excited to hear how it works for you and what we can do to improve it. 💜</p>
<h2 class="anchor anchorWithStickyNavbar_eAos" id="supporting-typescript-eslint">Supporting typescript-eslint<a href="https://typescript-eslint.io/blog/project-service#supporting-typescript-eslint" class="hash-link" aria-label="Direct link to Supporting typescript-eslint" title="Direct link to Supporting typescript-eslint">​</a></h2>
<p>If you enjoyed this blog post and/or use typescript-eslint, please consider <a href="https://opencollective.com/typescript-eslint" target="_blank" rel="noopener noreferrer">supporting us on Open Collective</a>. We're a small volunteer team and could use your support to make the ESLint experience on TypeScript great. Thanks! 💖</p>
<!-- -->
<section data-footnotes="true" class="footnotes"><h2 class="anchor anchorWithStickyNavbar_eAos sr-only" id="footnote-label">Footnotes<a href="https://typescript-eslint.io/blog/project-service#footnote-label" class="hash-link" aria-label="Direct link to Footnotes" title="Direct link to Footnotes">​</a></h2>
<ol>
<li id="user-content-fn-babel-conversion-a8f2db">
<p><a href="https://github.com/babel/babel/pull/16192#issue-2054613116" target="_blank" rel="noopener noreferrer">https://github.com/babel/babel/pull/16192#issue-2054613116</a> <a href="https://typescript-eslint.io/blog/project-service#user-content-fnref-babel-conversion-a8f2db" data-footnote-backref="" aria-label="Back to reference 1" class="data-footnote-backref">↩</a></p>
</li>
<li id="user-content-fn-create-t3-app-conversion-a8f2db">
<p><a href="https://github.com/t3-oss/create-t3-app/pull/1936/#discussion_r1667389041" target="_blank" rel="noopener noreferrer">https://github.com/t3-oss/create-t3-app/pull/1936/#discussion_r1667389041</a> <a href="https://typescript-eslint.io/blog/project-service#user-content-fnref-create-t3-app-conversion-a8f2db" data-footnote-backref="" aria-label="Back to reference 2" class="data-footnote-backref">↩</a></p>
</li>
<li id="user-content-fn-sveltekit-conversion-a8f2db">
<p><a href="https://github.com/sveltejs/kit/pull/13839" target="_blank" rel="noopener noreferrer">https://github.com/sveltejs/kit/pull/13839</a> <a href="https://typescript-eslint.io/blog/project-service#user-content-fnref-sveltekit-conversion-a8f2db" data-footnote-backref="" aria-label="Back to reference 3" class="data-footnote-backref">↩</a></p>
</li>
</ol>
</section>]]></content:encoded>
            <category>parser</category>
            <category>parser options</category>
            <category>project</category>
            <category>project service</category>
            <category>tsconfig</category>
        </item>
        <item>
            <title><![CDATA[Avoiding `any`s with Linting and TypeScript]]></title>
            <link>https://typescript-eslint.io/blog/avoiding-anys</link>
            <guid>https://typescript-eslint.io/blog/avoiding-anys</guid>
            <pubDate>Tue, 21 Jan 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[How typescript-eslint expands on TypeScript's type safety to catch explicit and implicit `any`s.]]></description>
            <content:encoded><![CDATA[<p>TypeScript's <code>any</code> type is, by design, the single most unsafe part of its type system.
The <code>any</code> type indicates a type that can be anything and can be used in place of any other type.
Using <code>any</code> is unsafe because the type disables many of TypeScript's type-checking features and hampers TypeScript's ability to provide developer assistance.</p>
<p>typescript-eslint includes several lint rules that help prevent unsafe practices around the <code>any</code> type.
These rules flag uses of <code>any</code> or code patterns that sneakily introduce it.</p>
<p>In this blog post, we'll show you those lint rules and several other handy ways to prevent <code>any</code>s from sneaking into your code.</p>
<!-- -->
<h2 class="anchor anchorWithStickyNavbar_eAos" id="noimplicitany-isnt-enough"><code>noImplicitAny</code> Isn't Enough<a href="https://typescript-eslint.io/blog/avoiding-anys#noimplicitany-isnt-enough" class="hash-link" aria-label="Direct link to noimplicitany-isnt-enough" title="Direct link to noimplicitany-isnt-enough">​</a></h2>
<p>TypeScript includes a <a href="https://www.typescriptlang.org/tsconfig/#noImplicitAny" target="_blank" rel="noopener noreferrer"><code>noImplicitAny</code></a> flag to report when a better type than <code>any</code> can't be inferred for a value.
<code>noImplicitAny</code> is part of its family of <a href="https://www.typescriptlang.org/tsconfig/#strict" target="_blank" rel="noopener noreferrer"><code>strict</code> compiler options</a> and is generally recommended for all projects.</p>
<p>However, even with <code>noImplicitAny</code> enabled, the <code>any</code> type can easily be introduced into codebases.
<code>noImplicitAny</code> doesn't prevent developers from explicitly writing the <code>any</code> type in type type annotations.
Some built-in APIs such as <code>JSON.stringify</code> and types such as <code>Function</code> can introduce the <code>any</code> type without triggering <code>noImplicitAny</code>.</p>
<p>Enabling <code>noImplicitAny</code> is a great first step towards better project type safety, but it's not enough to prevent <code>any</code>s altogether.</p>
<h2 class="anchor anchorWithStickyNavbar_eAos" id="banning-unsafe-types">Banning Unsafe Types<a href="https://typescript-eslint.io/blog/avoiding-anys#banning-unsafe-types" class="hash-link" aria-label="Direct link to Banning Unsafe Types" title="Direct link to Banning Unsafe Types">​</a></h2>
<p>The first line of defense against <code>any</code> for many repositories is adding lint rules that report on explicitly written unsafe types.
Developers can always <a href="https://eslint.org/docs/latest/use/configure/rules#using-configuration-comments-1" target="_blank" rel="noopener noreferrer">disable ESLint rules with inline comments</a>, so this isn't guaranteed to prevent explicit <code>any</code>s from popping up.
But these lint rules put an immediate restriction on unsafe types -- and help guide towards better alternatives.</p>
<h3 class="anchor anchorWithStickyNavbar_eAos" id="banning-explicit-anys">Banning Explicit <code>any</code>s<a href="https://typescript-eslint.io/blog/avoiding-anys#banning-explicit-anys" class="hash-link" aria-label="Direct link to banning-explicit-anys" title="Direct link to banning-explicit-anys">​</a></h3>
<p><a href="https://typescript-eslint.io/rules/no-explicit-any"><code>@typescript-eslint/no-explicit-any</code></a> reports on any instance of the <code>any</code> type written in your source code.
Doing so helps prevent developers from using <code>any</code> instead of a more safe type.</p>
<p>Take the following unsafe declaration of <code>friend: any</code> in a <code>greet</code> function.
Because its <code>friend</code> parameter is typed as <code>any</code> instead of <code>string</code>, TypeScript won't report a type error on a call that provides another type.
<code>@typescript-eslint/no-explicit-any</code> would report on that <code>any</code>:</p>
<div class="language-ts codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockContent_m3Ux"><pre class="prism-code language-ts codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line"><span class="token keyword">function</span><span class="token plain"> </span><span class="token function">greet</span><span class="token punctuation">(</span><span class="token plain">friend</span><span class="token operator">:</span><span class="token plain"> </span><span class="token builtin">any</span><span class="token punctuation">)</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token comment">//                   ~~~</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token comment">// eslint(@typescript-eslint/no-explicit-any):</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token comment">// Unexpected any. Specify a different type.</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token builtin">console</span><span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string template-punctuation string">`</span><span class="token template-string string">Hello, </span><span class="token template-string interpolation interpolation-punctuation punctuation">${</span><span class="token template-string interpolation">friend</span><span class="token template-string interpolation punctuation">.</span><span class="token template-string interpolation function">toUpperCase</span><span class="token template-string interpolation punctuation">(</span><span class="token template-string interpolation punctuation">)</span><span class="token template-string interpolation interpolation-punctuation punctuation">}</span><span class="token template-string string">!</span><span class="token template-string template-punctuation string">`</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token punctuation">}</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token function">greet</span><span class="token punctuation">(</span><span class="token string">'Lazlo'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token plain"> </span><span class="token comment">// Ok</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token function">greet</span><span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token plain"> name</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'Nadya'</span><span class="token plain"> </span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token plain"> </span><span class="token comment">// Should be a type error, but isn't</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Instead of <code>any</code>, it would have been more type safe to give <code>friend</code> the more precise type <code>string</code>.</p>
<h4 class="anchor anchorWithStickyNavbar_eAos" id="prefer-unknown">Prefer <code>unknown</code><a href="https://typescript-eslint.io/blog/avoiding-anys#prefer-unknown" class="hash-link" aria-label="Direct link to prefer-unknown" title="Direct link to prefer-unknown">​</a></h4>
<p>If you have data that is of an unknown type, instead of describing it with the unsafe <code>any</code> type, prefer the safer <code>unknown</code> instead.
<code>unknown</code> is almost always preferable because it doesn't allow using the value in any arbitrary, potentially unsafe way.</p>
<p><a href="https://typescript-eslint.io/rules/no-explicit-any"><code>@typescript-eslint/no-explicit-any</code></a>'s rule reports include a suggestion fixer that switches the explicit <code>any</code> to <code>unknown</code>.</p>
<h3 class="anchor anchorWithStickyNavbar_eAos" id="banning-function">Banning <code>Function</code><a href="https://typescript-eslint.io/blog/avoiding-anys#banning-function" class="hash-link" aria-label="Direct link to banning-function" title="Direct link to banning-function">​</a></h3>
<p><a href="https://typescript-eslint.io/rules/no-unsafe-function-type"><code>@typescript-eslint/no-unsafe-function-type</code></a> reports on any instance of the built-in <code>Function</code> type written in source code.
<code>Function</code> is a loose, unsafe type: it allows being called with any number of arguments and returns type <code>any</code>.</p>
<p>Take the following version of <code>greet</code> that takes in a function for its parameter.
<code>Function</code> doesn't describe any parameter or return types, so TypeScript can't know what types it's meant to take in or return.
<code>@typescript-eslint/no-unsafe-function-type</code> would report on that <code>Function</code>:</p>
<div class="language-ts codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockContent_m3Ux"><pre class="prism-code language-ts codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line"><span class="token keyword">function</span><span class="token plain"> </span><span class="token function">greet</span><span class="token punctuation">(</span><span class="token plain">getFriend</span><span class="token operator">:</span><span class="token plain"> </span><span class="token builtin">Function</span><span class="token punctuation">)</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token comment">//                      ~~~~~~~~</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token comment">// eslint(@typescript-eslint/no-unsafe-function-type):</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token comment">// The `Function` type accepts any function-like value.</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token comment">// Prefer explicitly defining any function parameters and return type.</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token builtin">console</span><span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string template-punctuation string">`</span><span class="token template-string string">Hello, </span><span class="token template-string interpolation interpolation-punctuation punctuation">${</span><span class="token template-string interpolation function">getFriend</span><span class="token template-string interpolation punctuation">(</span><span class="token template-string interpolation punctuation">)</span><span class="token template-string interpolation punctuation">.</span><span class="token template-string interpolation function">toUpperCase</span><span class="token template-string interpolation punctuation">(</span><span class="token template-string interpolation punctuation">)</span><span class="token template-string interpolation interpolation-punctuation punctuation">}</span><span class="token template-string string">!</span><span class="token template-string template-punctuation string">`</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token punctuation">}</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token function">greet</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token plain"> </span><span class="token operator">=&gt;</span><span class="token plain"> </span><span class="token string">'Lazlo'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token plain"> </span><span class="token comment">// Ok</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token function">greet</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token plain"> </span><span class="token operator">=&gt;</span><span class="token plain"> </span><span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token plain"> name</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'Nadya'</span><span class="token plain"> </span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token plain"> </span><span class="token comment">// Should be a type error, but isn't</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Instead of <code>Function</code>, it would have been more type safe to give <code>getFriend</code> the more precise type <code>() =&gt; string</code>.</p>
<h3 class="anchor anchorWithStickyNavbar_eAos" id="enforcing-unknown-for-caught-exceptions">Enforcing <code>unknown</code> for Caught Exceptions<a href="https://typescript-eslint.io/blog/avoiding-anys#enforcing-unknown-for-caught-exceptions" class="hash-link" aria-label="Direct link to enforcing-unknown-for-caught-exceptions" title="Direct link to enforcing-unknown-for-caught-exceptions">​</a></h3>
<p>There is no way to indicate what types functions may throw in TypeScript, due to the highly dynamic nature of JavaScript<sup><a href="https://typescript-eslint.io/blog/avoiding-anys#user-content-fn-no-throws-204727" id="user-content-fnref-no-throws-204727" data-footnote-ref="true" aria-describedby="footnote-label">1</a></sup>.
Therefore, TypeScript treats all caught values as <code>any</code> by default.
TypeScript's <a href="https://www.typescriptlang.org/tsconfig/#useUnknownInCatchVariables" target="_blank" rel="noopener noreferrer"><code>useUnknownInCatchVariables</code></a> changes <code>catch</code> block variables to have the more appropriate <code>unknown</code> type, but no compiler option equivalent exists for <code>Promise</code> rejections' <code>.catch()</code> method.</p>
<p><a href="https://typescript-eslint.io/rules/use-unknown-in-catch-callback-variable"><code>@typescript-eslint/use-unknown-in-catch-callback-variable</code></a> enforces always using the <code>unknown</code> type for the parameter of a Promise rejection callback.</p>
<p>For example, given the following code, TypeScript would not report a type error, but the lint rule would report:</p>
<div class="language-ts codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockContent_m3Ux"><pre class="prism-code language-ts codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line"><span class="token keyword">function</span><span class="token plain"> </span><span class="token function">rejectWith</span><span class="token punctuation">(</span><span class="token plain">value</span><span class="token operator">:</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token punctuation">)</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token keyword">return</span><span class="token plain"> </span><span class="token builtin">Promise</span><span class="token punctuation">.</span><span class="token function">reject</span><span class="token punctuation">(</span><span class="token plain">value</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token punctuation">}</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token function">rejectWith</span><span class="token punctuation">(</span><span class="token string">'Nandor'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">catch</span><span class="token punctuation">(</span><span class="token plain">error </span><span class="token operator">=&gt;</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token comment">//                       ~~~~~</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token comment">// eslint(@typescript-eslint/use-unknown-in-catch-callback-variable):</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token comment">// Prefer the safe `: unknown` for a `catch` callback variable.</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token builtin">console</span><span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token plain">error</span><span class="token punctuation">.</span><span class="token plain">message</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token plain"> </span><span class="token comment">// Should be a type error, but isn't</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Had the <code>error</code> been given a <code>: unknown</code> type, TypeScript would be able to report on <code>error.message</code> as being unsafe.</p>
<h2 class="anchor anchorWithStickyNavbar_eAos" id="banning-usage-of-unsafe-types">Banning Usage of Unsafe Types<a href="https://typescript-eslint.io/blog/avoiding-anys#banning-usage-of-unsafe-types" class="hash-link" aria-label="Direct link to Banning Usage of Unsafe Types" title="Direct link to Banning Usage of Unsafe Types">​</a></h2>
<p>Once an <code>any</code> type exists in code, it is "infectious": it can turn the types of values based on it into more <code>any</code>s.</p>
<p>typescript-eslint includes a collection of rules that flag code patterns which make use of <code>any</code>'s unsafe, viral nature.
Each of the following rules reports on a specific use of <code>any</code>.</p>
<ul>
<li><a href="https://typescript-eslint.io/rules/no-unsafe-argument"><code>@typescript-eslint/no-unsafe-argument</code></a> reports on passing an <code>any</code> typed value to a function call</li>
<li><a href="https://typescript-eslint.io/rules/no-unsafe-assignment"><code>@typescript-eslint/no-unsafe-assignment</code></a> reports on assigning an <code>any</code> typed value to a property or variable</li>
<li><a href="https://typescript-eslint.io/rules/no-unsafe-call"><code>@typescript-eslint/no-unsafe-call</code></a> reports on calling an <code>any</code> typed value like a function</li>
<li><a href="https://typescript-eslint.io/rules/no-unsafe-member-access"><code>@typescript-eslint/no-unsafe-member-access</code></a> reports on accessing members of any value typed as <code>any</code></li>
<li><a href="https://typescript-eslint.io/rules/no-unsafe-return"><code>@typescript-eslint/no-unsafe-return</code></a> reports on returning a value typed as <code>any</code> from a function</li>
</ul>
<p>For example, this <code>parseData</code> function violates several of those lint rules by creating a <code>shape</code> value of type <code>any</code> and not validating its type before using it:</p>
<div class="language-ts codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockContent_m3Ux"><pre class="prism-code language-ts codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line"><span class="token keyword">export</span><span class="token plain"> </span><span class="token keyword">interface</span><span class="token plain"> </span><span class="token class-name">Shape</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  label</span><span class="token operator">:</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  value</span><span class="token operator">:</span><span class="token plain"> </span><span class="token builtin">number</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token punctuation">}</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token keyword">export</span><span class="token plain"> </span><span class="token keyword">function</span><span class="token plain"> </span><span class="token function">parseShapeFromData</span><span class="token punctuation">(</span><span class="token plain">raw</span><span class="token operator">:</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token punctuation">)</span><span class="token operator">:</span><span class="token plain"> Shape </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token keyword">const</span><span class="token plain"> shape </span><span class="token operator">=</span><span class="token plain"> </span><span class="token constant">JSON</span><span class="token punctuation">.</span><span class="token function">parse</span><span class="token punctuation">(</span><span class="token plain">raw</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token comment">//    ~~~~~~~~~~~~~~~~~~~~~~~</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token comment">// eslint(@typescript-eslint/no-unsafe-assignment):</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token comment">// Unsafe assignment of an `any` value.</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token builtin">console</span><span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Making a shape with value:'</span><span class="token punctuation">,</span><span class="token plain"> shape</span><span class="token punctuation">.</span><span class="token plain">value</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token comment">//                                              ~~~~~</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token comment">// eslint(@typescript-eslint/no-unsafe-member-access):</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token comment">// Unsafe member access .value of an `any` value.</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token keyword">return</span><span class="token plain"> shape</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token comment">// eslint(@typescript-eslint/no-unsafe-return):</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token comment">// Unsafe return of an `any` value.</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token punctuation">}</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Had the <code>parseShapeFromData</code> function included checks on the type of the <code>shape</code> value or used a schema validation library such as <a href="https://zod.dev/" target="_blank" rel="noopener noreferrer">Zod</a>, it would be informed at runtime if its <code>raw</code> string didn't create the expected <code>Shape</code>.</p>
<p>Put together, the <code>@typescript-eslint/no-unusafe-*</code> rules around <code>any</code> safety provide a comprehensive suite of checks that can flag most accidental uses of <code>any</code> across a codebase.
We highly recommend using them alongside TypeScript's <code>noImplicitAny</code> compiler option.</p>
<h2 class="anchor anchorWithStickyNavbar_eAos" id="additional-helpers">Additional Helpers<a href="https://typescript-eslint.io/blog/avoiding-anys#additional-helpers" class="hash-link" aria-label="Direct link to Additional Helpers" title="Direct link to Additional Helpers">​</a></h2>
<h3 class="anchor anchorWithStickyNavbar_eAos" id="disabling-typescript-suppressions">Disabling TypeScript Suppressions<a href="https://typescript-eslint.io/blog/avoiding-anys#disabling-typescript-suppressions" class="hash-link" aria-label="Direct link to Disabling TypeScript Suppressions" title="Direct link to Disabling TypeScript Suppressions">​</a></h3>
<p>The <code>any</code> type is not the only way to bypass TypeScript's type system.
Developers are also able to use inline TypeScript directives: <code>// @ts-expect-error</code> and <code>// @ts-ignore</code>.
Those inline comment directives cause TypeScript to ignore type errors on a line.
Disabling TypeScript on a per-line basis can sometimes be necessary in rare cases, but is always unsafe and should not be part of your standard toolkit.</p>
<div class="theme-admonition theme-admonition-tip admonition_pzuZ alert alert--success"><div class="admonitionHeading_uJho"><span class="admonitionIcon_vMH2"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>tip</div><div class="admonitionContent_gazR"><p><code>// @ts-expect-error</code> and <code>// @ts-ignore</code> are almost the same, except <code>// @ts-expect-error</code> will produce a new error if there isn't any existing error for it to suppress.
It's generally preferable to use <code>// @ts-expect-error</code> over <code>// @ts-ignore</code>.</p></div></div>
<p><a href="https://typescript-eslint.io/rules/ban-ts-comment"><code>@typescript-eslint/ban-comment</code></a> can be used to report on cases where developers use TypeScript comment directives.
By default, the rule:</p>
<ul>
<li>Prohibits all <code>@ts-ignore</code> and <code>@ts-nocheck</code> comment directives</li>
<li>Prohibits <code>@ts-expect-error</code> directives unless they have an explanatory comment description</li>
<li>Requires explanatory comment descriptions to contain at least 3 characters</li>
</ul>
<p>For example, suppose <code>"@example/package"</code> exports a <code>processString</code> function that should take in a <code>string</code> but whose types incorrectly indicate take in a <code>number</code>.
A <code>// @ts-expect-error</code> comment could be used to tell TypeScript to ignore the line:</p>
<div class="tabs-container tabList_hoTN"><ul role="tablist" aria-orientation="horizontal" class="tabs"><li role="tab" tabindex="0" aria-selected="true" class="tabs__item tabItem_dW3K tabs__item--active">❌ Incorrect</li><li role="tab" tabindex="-1" aria-selected="false" class="tabs__item tabItem_dW3K">✅ Correct</li></ul><div class="margin-top--md"><div role="tabpanel" class="tabItem_PzSZ"><div class="language-ts codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockContent_m3Ux"><pre class="prism-code language-ts codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line"><span class="token keyword">import</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"> processString </span><span class="token punctuation">}</span><span class="token plain"> </span><span class="token keyword">from</span><span class="token plain"> </span><span class="token string">'@example/package'</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token comment">// @ts-ignore</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token function">processString</span><span class="token punctuation">(</span><span class="token string">'New York City'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div></div><div role="tabpanel" class="tabItem_PzSZ" hidden=""><div class="language-ts codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockContent_m3Ux"><pre class="prism-code language-ts codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line"><span class="token keyword">import</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"> processString </span><span class="token punctuation">}</span><span class="token plain"> </span><span class="token keyword">from</span><span class="token plain"> </span><span class="token string">'@example/package'</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token comment">// @ts-expect-error -- Pending updating the processString types. See GH-1234.</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token function">processString</span><span class="token punctuation">(</span><span class="token string">'New York City'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div></div></div></div>
<p>Once the types for <code>@example/package</code> are fixed to no longer produce a type error, the comment directive will itself produce a type error asking to delete itself.</p>
<h3 class="anchor anchorWithStickyNavbar_eAos" id="eslint-comments-plugin">ESLint Comments Plugin<a href="https://typescript-eslint.io/blog/avoiding-anys#eslint-comments-plugin" class="hash-link" aria-label="Direct link to ESLint Comments Plugin" title="Direct link to ESLint Comments Plugin">​</a></h3>
<p>ESLint includes its own inline comment directives separate from TypeScript's.
<code>// eslint-disable</code>, <code>// eslint-disable-next-line</code>, and other inline ESLint config comments can suppress lint rules — including those mentioned in this post.
Suppressing ESLint rules can also be necessary in cases where the rule and/or TypeScript's type system have misunderstand your code.</p>
<p>If you must use ESLint comment directives, we recommend utilizing <a href="https://eslint-community.github.io/eslint-plugin-eslint-comments" target="_blank" rel="noopener noreferrer"><code>@eslint-community/eslint-plugin-eslint-comments</code></a>.
The plugin's <a href="https://eslint-community.github.io/eslint-plugin-eslint-comments/#%F0%9F%93%96-usage" target="_blank" rel="noopener noreferrer">recommended preset</a> enables rules that enforce best practices around ESLint comment directives, including:</p>
<ul>
<li><a href="https://eslint-community.github.io/eslint-plugin-eslint-comments/rules/disable-enable-pair.html" target="_blank" rel="noopener noreferrer"><code>@eslint-community/eslint-comments/disable-enable-pair</code></a>: to prevent accidentally disabling rules for the rest of a file, rather than on specific lines</li>
<li><a href="https://eslint-community.github.io/eslint-plugin-eslint-comments/rules/no-unlimited-disable.html" target="_blank" rel="noopener noreferrer"><code>@eslint-community/eslint-comments/no-unlimited-disable</code></a>: to prevent accidentally disabling all ESLint rules, rather than specific ones</li>
<li><a href="https://eslint-community.github.io/eslint-plugin-eslint-comments/rules/require-description.html" target="_blank" rel="noopener noreferrer"><code>@eslint-community/eslint-comments/require-description</code></a>: to require comments explaining why directives are necessary</li>
</ul>
<p>For example, suppose the type of an imported variable is temporarily <code>any</code> pending some soon-to-be-completed refactoring.
It might be reasonable to include an ESLint disable comment to suppress a lint rule reporting on the <code>any</code>.
That comment should ideally include an explanation and link to the pending task, so developers know it's not normal to disable lint rules without good reason:</p>
<div class="tabs-container tabList_hoTN"><ul role="tablist" aria-orientation="horizontal" class="tabs"><li role="tab" tabindex="0" aria-selected="true" class="tabs__item tabItem_dW3K tabs__item--active">❌ Incorrect</li><li role="tab" tabindex="-1" aria-selected="false" class="tabs__item tabItem_dW3K">✅ Correct</li></ul><div class="margin-top--md"><div role="tabpanel" class="tabItem_PzSZ"><div class="language-ts codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockContent_m3Ux"><pre class="prism-code language-ts codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line"><span class="token keyword">import</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"> processString </span><span class="token punctuation">}</span><span class="token plain"> </span><span class="token keyword">from</span><span class="token plain"> </span><span class="token string">'@example/package'</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token comment">// eslint-disable-next-line @typescript-eslint/no-unsafe-call</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token function">processString</span><span class="token punctuation">(</span><span class="token string">'New York City'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div></div><div role="tabpanel" class="tabItem_PzSZ" hidden=""><div class="language-ts codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockContent_m3Ux"><pre class="prism-code language-ts codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line"><span class="token keyword">import</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"> processString </span><span class="token punctuation">}</span><span class="token plain"> </span><span class="token keyword">from</span><span class="token plain"> </span><span class="token string">'@example/package'</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token comment">// Pending GH-1234: will soon not be any.</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token comment">// eslint-disable-next-line @typescript-eslint/no-unsafe-call</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token function">processString</span><span class="token punctuation">(</span><span class="token string">'New York City'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div></div></div></div>
<p>Once the types for <code>@example/package</code> are fixed to no longer produce an <code>any</code>, running ESLint with <a href="https://eslint.org/docs/latest/use/configure/rules#report-unused-eslint-disable-comments" target="_blank" rel="noopener noreferrer"><code>reportUnusedDisableDirectives</code></a> option will produce a lint report asking to remove the comment directive.</p>
<h3 class="anchor anchorWithStickyNavbar_eAos" id="ts-reset"><code>ts-reset</code><a href="https://typescript-eslint.io/blog/avoiding-anys#ts-reset" class="hash-link" aria-label="Direct link to ts-reset" title="Direct link to ts-reset">​</a></h3>
<p>Some sources of <code>any</code> come from built-in global types provided by TypeScript.
<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse" target="_blank" rel="noopener noreferrer"><code>JSON.parse()</code></a>, <a href="https://developer.mozilla.org/en-US/docs/Web/API/Response/json" target="_blank" rel="noopener noreferrer"><code>.json()</code></a>, and <a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API/Using_the_Web_Storage_API#basic_concepts" target="_blank" rel="noopener noreferrer"><code>Storage</code></a> properties are all typed as <code>any</code> by default in TypeScript.
TypeScript keeps <code>any</code> in the types for legacy support reasons<sup><a href="https://typescript-eslint.io/blog/avoiding-anys#user-content-fn-compiler-option-lib-any-204727" id="user-content-fnref-compiler-option-lib-any-204727" data-footnote-ref="true" aria-describedby="footnote-label">2</a></sup>.</p>
<p>The <a href="https://www.totaltypescript.com/ts-reset" target="_blank" rel="noopener noreferrer"><code>ts-reset</code></a> library switches those global type definitions to safer equivalents.
It switches the <code>any</code>s in those built-in types to <code>unknown</code>.</p>
<p>With <code>ts-reset</code>, the following <code>data</code> variable would switch from being type <code>any</code> to <code>unknown</code>:</p>
<div class="language-ts codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockContent_m3Ux"><pre class="prism-code language-ts codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line"><span class="token keyword">const</span><span class="token plain"> data </span><span class="token operator">=</span><span class="token plain"> </span><span class="token constant">JSON</span><span class="token punctuation">.</span><span class="token function">parse</span><span class="token punctuation">(</span><span class="token template-string template-punctuation string">`</span><span class="token template-string string">"clearly-a-string"</span><span class="token template-string template-punctuation string">`</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token comment">//    ^? any (without ts-reset)</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token comment">//    ^? unknown (with ts-reset)</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token builtin">console</span><span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token plain">data</span><span class="token punctuation">.</span><span class="token plain">some</span><span class="token punctuation">.</span><span class="token plain">property</span><span class="token punctuation">.</span><span class="token plain">that</span><span class="token punctuation">.</span><span class="token plain">does</span><span class="token punctuation">.</span><span class="token plain">not</span><span class="token punctuation">.</span><span class="token plain">exist</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Note that <code>ts-reset</code> applies globally, so it should only be used in application code.</p>
<h2 class="anchor anchorWithStickyNavbar_eAos" id="next-steps">Next Steps<a href="https://typescript-eslint.io/blog/avoiding-anys#next-steps" class="hash-link" aria-label="Direct link to Next Steps" title="Direct link to Next Steps">​</a></h2>
<p>We highly recommend using at least the <a href="https://typescript-eslint.io/users/configs#recommended-type-checked"><code>tseslint.configs.recommendedTypeChecked</code></a> preset in your ESLint configuration.
It enables the <code>no-explicit-any</code> and <code>no-unsafe-*</code> lint rules mentioned in this blog post, as well as a large set of other rules that help enforce type safety and TypeScript best practices.</p>
<p>If you're interested in achieving stronger type safety with more strict linting, consider upgrading to the <a href="https://typescript-eslint.io/users/configs#strict-type-checked"><code>tseslint.configs.strictTypeChecked</code></a> preset.
It includes all the recommended rules, as well as <code>use-unknown-in-catch-callback-variable</code> and other rules that enforce more strict type safety and TypeScript best practices.</p>
<!-- -->
<section data-footnotes="true" class="footnotes"><h2 class="anchor anchorWithStickyNavbar_eAos sr-only" id="footnote-label">Footnotes<a href="https://typescript-eslint.io/blog/avoiding-anys#footnote-label" class="hash-link" aria-label="Direct link to Footnotes" title="Direct link to Footnotes">​</a></h2>
<ol>
<li id="user-content-fn-no-throws-204727">
<p><a href="https://www.learningtypescript.com/articles/why-typescript-doesnt-include-a-throws-keyword" target="_blank" rel="noopener noreferrer">Why TypeScript Doesn't Include a <code>throws</code> Keyword</a> <a href="https://typescript-eslint.io/blog/avoiding-anys#user-content-fnref-no-throws-204727" data-footnote-backref="" aria-label="Back to reference 1" class="data-footnote-backref">↩</a></p>
</li>
<li id="user-content-fn-compiler-option-lib-any-204727">
<p><a href="https://github.com/microsoft/TypeScript/issues/60899" target="_blank" rel="noopener noreferrer">microsoft/TypeScript#60899 Compiler option to switch lib .d.ts anys to unknown</a> <a href="https://typescript-eslint.io/blog/avoiding-anys#user-content-fnref-compiler-option-lib-any-204727" data-footnote-backref="" aria-label="Back to reference 2" class="data-footnote-backref">↩</a></p>
</li>
</ol>
</section>]]></content:encoded>
            <category>any</category>
            <category>no-explicit-any</category>
            <category>no-unsafe</category>
            <category>noImplicitAny</category>
            <category>typed linting</category>
        </item>
        <item>
            <title><![CDATA[Typed Linting: The Most Powerful TypeScript Linting Ever]]></title>
            <link>https://typescript-eslint.io/blog/typed-linting</link>
            <guid>https://typescript-eslint.io/blog/typed-linting</guid>
            <pubDate>Mon, 30 Sep 2024 00:00:00 GMT</pubDate>
            <description><![CDATA[Explaining what linting with type information means, why it's so powerful, and some of the useful rules you can enable that use it.]]></description>
            <content:encoded><![CDATA[<p><a href="https://typescript-eslint.io/getting-started/typed-linting" target="_blank" rel="noopener noreferrer">Linting with type information</a>, also called "typed linting" or "type-aware linting", is the act of writing lint rules that use type information to understand your code.
Typed linting rules as provided by typescript-eslint are the most powerful JavaScript/TypeScript linting in common use today.</p>
<p>In this blog post, we'll give a high-level overview of how linting with type information works, why it's so much more powerful than traditional linting, and some of the useful rules you can enable that use it.</p>
<h2 class="anchor anchorWithStickyNavbar_eAos" id="recap-type-information">Recap: Type Information?<a href="https://typescript-eslint.io/blog/typed-linting#recap-type-information" class="hash-link" aria-label="Direct link to Recap: Type Information?" title="Direct link to Recap: Type Information?">​</a></h2>
<p>Traditional JavaScript lint rules operate on one file at a time.
They look at a description of code in each file and report complaints if that file seems to contain bad practices.
That description is called an Abstract Syntax Tree, or AST.</p>
<div class="theme-admonition theme-admonition-tip admonition_pzuZ alert alert--success"><div class="admonitionHeading_uJho"><span class="admonitionIcon_vMH2"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>tip</div><div class="admonitionContent_gazR"><p>For a primer on ASTs and linting, see <em><a href="https://typescript-eslint.io/blog/asts-and-typescript-eslint">ASTs and typescript-eslint</a></em>.</p></div></div>
<p>Each file's AST contains only information for that file, not any other files.
Lint rules that rely only on the file's AST don't have a way to understand code imported from other files, such as in ESM <code>import</code> statements.
Not being able to understand code from other files severely limits lint rules.</p>
<p>As an example, suppose you enable a lint rule like <a href="https://typescript-eslint.io/rules/no-deprecated"><code>@typescript-eslint/no-deprecated</code></a> to prevent calling to code with a <code>@deprecated</code> JSDoc.
Using just the following file's AST, the lint rule would have no way of knowing whether <code>work</code> is deprecated:</p>
<div class="language-ts codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockTitle_P25_">index.ts</div><div class="codeBlockContent_m3Ux"><pre class="prism-code language-ts codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line"><span class="token keyword">import</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"> work </span><span class="token punctuation">}</span><span class="token plain"> </span><span class="token keyword">from</span><span class="token plain"> </span><span class="token string">'./worker'</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token comment">// Is this safe? Does calling work violate any rules? We don't know!</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token function">work</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p><em>Type information</em> refers to the information a type checker such as TypeScript generates to understand your code.
Type checkers read code, determine what types each value may be, and store that "type information".
TypeScript and tools that call to TypeScript's APIs can then use that type information to understand the project's code.</p>
<p>In the earlier example, type information would be able to inform a lint rule running in <code>index.ts</code> that the <code>work</code> import resolves to a function in another file:</p>
<div class="language-ts codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockTitle_P25_">worker.ts</div><div class="codeBlockContent_m3Ux"><pre class="prism-code language-ts codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line"><span class="token doc-comment comment">/** </span><span class="token doc-comment comment keyword">@deprecated</span><span class="token doc-comment comment"> - Don't do this! */</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token keyword">export</span><span class="token plain"> </span><span class="token keyword">function</span><span class="token plain"> </span><span class="token function">work</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token comment">// ...</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token punctuation">}</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>...which would allow the lint rule to report a complaint that the <code>work()</code> call is to a function marked as <code>@deprecated</code>.</p>
<p>typescript-eslint allows lint rules to retrieve type information using TypeScript's APIs.
In doing so, they can even make decisions on linted files using information outside each individual file.</p>
<h2 class="anchor anchorWithStickyNavbar_eAos" id="common-uses-for-typed-linting">Common Uses for Typed Linting<a href="https://typescript-eslint.io/blog/typed-linting#common-uses-for-typed-linting" class="hash-link" aria-label="Direct link to Common Uses for Typed Linting" title="Direct link to Common Uses for Typed Linting">​</a></h2>
<p>Cross-file type information is a powerful addition to lint rules.
Knowing the types of pieces of your code allows lint rules to flag for risky behavior specific to certain types.
The following sections show several of the most common uses for lint rules that rely on type information.</p>
<h3 class="anchor anchorWithStickyNavbar_eAos" id="unsafe-anys">Unsafe <code>any</code>s<a href="https://typescript-eslint.io/blog/typed-linting#unsafe-anys" class="hash-link" aria-label="Direct link to unsafe-anys" title="Direct link to unsafe-anys">​</a></h3>
<p>The <code>@typescript-eslint/no-unsafe-*</code> family of rules checks for risky uses of <code>any</code> typed values.
This is useful because the <code>any</code> type can easily slip into code and reduce type safety, despite being allowed by the TypeScript type checker.</p>
<p>For example, the following code that logs a member of an object parsed from a string produces no type errors in type checking.
<code>JSON.parse()</code> returns <code>any</code>, and arbitrary property accesses are allowed on values of type <code>any</code>.</p>
<p>However, <a href="https://typescript-eslint.io/rules/no-unsafe-member-access"><code>@typescript-eslint/no-unsafe-member-access</code></a> would report <code>[key]</code> might not be a property on the object:</p>
<div class="language-ts codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockContent_m3Ux"><pre class="prism-code language-ts codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line"><span class="token keyword">function</span><span class="token plain"> </span><span class="token function">getDataKey</span><span class="token punctuation">(</span><span class="token plain">rawData</span><span class="token operator">:</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token punctuation">,</span><span class="token plain"> key</span><span class="token operator">:</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token punctuation">)</span><span class="token operator">:</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token keyword">return</span><span class="token plain"> </span><span class="token constant">JSON</span><span class="token punctuation">.</span><span class="token function">parse</span><span class="token punctuation">(</span><span class="token plain">rawData</span><span class="token punctuation">)</span><span class="token punctuation">[</span><span class="token plain">key</span><span class="token punctuation">]</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token comment">//                        ~~~~~</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token comment">// Unsafe member access [key] on an `any` value.</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token comment">// eslint(@typescript-eslint/no-unsafe-member-access)</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token punctuation">}</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>The lint rule is right to report.
Calls to the <code>getDataKey</code> function can return a value that's not a <code>string</code>, despite the function's explicit return type annotation.
That can lead to unexpected behavior at runtime:</p>
<div class="language-ts codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockContent_m3Ux"><pre class="prism-code language-ts codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line"><span class="token builtin">console</span><span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token function">getDataKey</span><span class="token punctuation">(</span><span class="token template-string template-punctuation string">`</span><span class="token template-string string">{ "blue": "cheese" }</span><span class="token template-string template-punctuation string">`</span><span class="token punctuation">,</span><span class="token plain"> </span><span class="token string">'bleu'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toUpperCase</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token comment">// Uncaught TypeError: Cannot read properties of undefined (reading 'toUpperCase')</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Without type information to indicate the types of <code>JSON.parse</code> and <code>key</code>, there would have been no way to determine that the <code>[key]</code> member access was unsafe.</p>
<h3 class="anchor anchorWithStickyNavbar_eAos" id="method-call-scoping">Method Call Scoping<a href="https://typescript-eslint.io/blog/typed-linting#method-call-scoping" class="hash-link" aria-label="Direct link to Method Call Scoping" title="Direct link to Method Call Scoping">​</a></h3>
<p>Runtime crashes caused by misuses of typed code are possible even with no <code>any</code>s.</p>
<p>For example, class method functions don't preserve their class scope when passed as standalone variables ("unbound").
TypeScript still allows them to be called without the proper <code>this</code> scope.</p>
<p>The global <code>localStorage</code> object in browsers has several properties that must be called with a <code>this</code> bound to <code>localStorage</code>.
The <a href="https://typescript-eslint.io/rules/unbound-method"><code>@typescript-eslint/unbound-method</code></a> lint rule can report on unsafe references to those properties, such as accessing <code>getItem</code>:</p>
<div class="language-ts codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockContent_m3Ux"><pre class="prism-code language-ts codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line"><span class="token keyword">const</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"> getItem </span><span class="token punctuation">}</span><span class="token plain"> </span><span class="token operator">=</span><span class="token plain"> localStorage</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token comment">//      ~~~~~~~</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token comment">// Avoid referencing unbound methods which may cause unintentional scoping of `this`.</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token comment">// eslint(@typescript-eslint/unbound-method)</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>That's useful because calls to <code>getItem</code> that aren't bound to <code>localStorage</code> cause an exception at runtime:</p>
<div class="language-ts codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockContent_m3Ux"><pre class="prism-code language-ts codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line"><span class="token function">getItem</span><span class="token punctuation">(</span><span class="token string">'...'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token comment">// Uncaught TypeError: Illegal invocation</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Without type information to indicate the types of <code>localStorage</code> and its <code>getItem</code> property, there would have been no reliable way to determine that the <code>const { getItem }</code> access was unsafe.</p>
<h3 class="anchor anchorWithStickyNavbar_eAos" id="async-race-conditions">Async Race Conditions<a href="https://typescript-eslint.io/blog/typed-linting#async-race-conditions" class="hash-link" aria-label="Direct link to Async Race Conditions" title="Direct link to Async Race Conditions">​</a></h3>
<p>Even if your code is 100% typed, has no <code>any</code>s, and doesn't misuse scopes, it's still possible to have bugs that can only easily be detected by typed linting.
Asynchronous code with <code>Promise</code>s in particular can introduce subtle issues that are completely type-safe.</p>
<p>Suppose your code is meant to run an asynchronous <code>readFromCache</code> function before reading from the file system:</p>
<div class="language-ts codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockContent_m3Ux"><pre class="prism-code language-ts codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line"><span class="token keyword">import</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"> fs </span><span class="token punctuation">}</span><span class="token plain"> </span><span class="token keyword">from</span><span class="token plain"> </span><span class="token string">'node:fs/promises'</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token keyword">import</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"> readFromCache </span><span class="token punctuation">}</span><span class="token plain"> </span><span class="token keyword">from</span><span class="token plain"> </span><span class="token string">'./caching'</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token keyword">const</span><span class="token plain"> filePath </span><span class="token operator">=</span><span class="token plain"> </span><span class="token string">'./data.json'</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token function">readFromCache</span><span class="token punctuation">(</span><span class="token plain">filePath</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token keyword">await</span><span class="token plain"> fs</span><span class="token punctuation">.</span><span class="token function">rm</span><span class="token punctuation">(</span><span class="token plain">filePath</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Do you see the potential bug?</p>
<p>If <code>readFromCache</code> is asynchronous (returns a <code>Promise</code>), then calling it and not awaiting its returned Promise could lead to race conditions in code.
Its asynchronous or delayed logic might not get to reading from the <code>filePath</code> before <code>fs.rm(filePath)</code> runs.</p>
<p>This is commonly referred to as a <em>"floating"</em> Promise: one that is created but not appropriately handled.
The <a href="https://typescript-eslint.io/rules/no-floating-promises"><code>@typescript-eslint/no-floating-promises</code></a> lint rule would report on that floating Promise:</p>
<div class="language-ts codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockContent_m3Ux"><pre class="prism-code language-ts codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line"><span class="token function">readFromCache</span><span class="token punctuation">(</span><span class="token plain">filePath</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token comment">// Promises must be awaited, end with a call to .catch, end with a call to .then</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token comment">// with a rejection handler or be explicitly marked as ignored with the `void` operator.</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token comment">// eslint(@typescript-eslint/no-floating-promises</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>...and can give an editor suggestion to add a missing <code>await</code>:</p>
<div class="language-diff codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockContent_m3Ux"><pre class="prism-code language-diff codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line"><span class="token deleted-sign deleted prefix deleted">-</span><span class="token deleted-sign deleted line"> readFromCache(filePath);</span><br></span><span class="token-line"><span class="token deleted-sign deleted line"></span><span class="token inserted-sign inserted prefix inserted">+</span><span class="token inserted-sign inserted line"> await readFromCache(filePath);</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Determining whether code is creating a floating Promise is only possible when the types of code are known.
Otherwise, lint rules would have no way of knowing which imports from other files could potentially create a Promise that needs to be handled.</p>
<h3 class="anchor anchorWithStickyNavbar_eAos" id="custom-rules">Custom Rules<a href="https://typescript-eslint.io/blog/typed-linting#custom-rules" class="hash-link" aria-label="Direct link to Custom Rules" title="Direct link to Custom Rules">​</a></h3>
<p>Typed linting isn't restricted to just typescript-eslint rules.
It can be used in community ESLint plugins, as well as custom rules specific to your project.</p>
<p>One common example used by teams is to codemod from a deprecated API to its replacement.
Typed linting is often necessary to determine which pieces of code call to the old API.</p>
<p>As an example, consider the following <code>fetch()</code> POST call that sends data to an intake API.
Suppose the intake endpoint is migrating from sending <code>[string, string]</code> tuples to sending key-value pairs.
A typed lint rule could determine that the data is in the old format:</p>
<div class="language-ts codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockContent_m3Ux"><pre class="prism-code language-ts codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line"><span class="token keyword">import</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"> endpoints </span><span class="token punctuation">}</span><span class="token plain"> </span><span class="token keyword">from</span><span class="token plain"> </span><span class="token string">"~/api"</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token keyword">const</span><span class="token plain"> rawData </span><span class="token operator">=</span><span class="token plain"> </span><span class="token punctuation">[</span><span class="token string">"key"</span><span class="token punctuation">,</span><span class="token plain"> </span><span class="token string">"value"</span><span class="token punctuation">]</span><span class="token plain"> </span><span class="token keyword">as</span><span class="token plain"> </span><span class="token keyword">const</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token keyword">await</span><span class="token plain"> </span><span class="token function">fetch</span><span class="token punctuation">(</span><span class="token plain">endpoints</span><span class="token punctuation">.</span><span class="token plain">intake</span><span class="token punctuation">,</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  data</span><span class="token operator">:</span><span class="token plain"> </span><span class="token constant">JSON</span><span class="token punctuation">.</span><span class="token function">stringify</span><span class="token punctuation">(</span><span class="token plain">rawData</span><span class="token punctuation">)</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token comment">//                   ~~~~~~~</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token comment">// Don't pass a tuple to endpoints.intake. Pass a key-value object instead.</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token comment">// eslint(@my-team/custom-rule)</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token comment">// ...</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  method</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">"POST"</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>...and provide a code fix to automatically migrate to the new format:</p>
<div class="language-diff codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockContent_m3Ux"><pre class="prism-code language-diff codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line"><span class="token plain">import { endpoints } from "~/api";</span><br></span><span class="token-line"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line"><span class="token plain">const rawData = ["key", "value"] as const;</span><br></span><span class="token-line"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line"><span class="token plain">await fetch(endpoints.intake, {</span><br></span><span class="token-line"><span class="token plain"></span><span class="token deleted-sign deleted prefix deleted">-</span><span class="token deleted-sign deleted line"> data: JSON.stringify(rawData)</span><br></span><span class="token-line"><span class="token deleted-sign deleted line"></span><span class="token inserted-sign inserted prefix inserted">+</span><span class="token inserted-sign inserted line"> data: JSON.stringify(Object.fromEntries(rawData))</span><br></span><span class="token-line"><span class="token inserted-sign inserted line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line"> // ...</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line"> method: "POST",</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token plain">});</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Knowing that the <code>fetch()</code> call was being sent to <code>endpoints.intake</code> and that the type of the data was a tuple takes typed linting.</p>
<p>That kind of migration codemod is one of the ways typed linting can be utilized for project- or team-specific rules.
See <a href="https://typescript-eslint.io/developers/custom-rules">Developers &gt; Custom Rules</a> for more documentation on building your own ESLint rules with typescript-eslint.</p>
<h2 class="anchor anchorWithStickyNavbar_eAos" id="enabling-typed-linting">Enabling Typed Linting<a href="https://typescript-eslint.io/blog/typed-linting#enabling-typed-linting" class="hash-link" aria-label="Direct link to Enabling Typed Linting" title="Direct link to Enabling Typed Linting">​</a></h2>
<p>You can add typed linting to your ESLint configuration by following the steps in <a href="https://typescript-eslint.io/getting-started/typed-linting">Linting with Type Information</a>.
We recommend doing so by enabling <a href="https://typescript-eslint.io/packages/parser#projectservice"><code>parserOptions.projectService</code></a>:</p>
<div class="language-js codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockTitle_P25_">eslint.config.js</div><div class="codeBlockContent_m3Ux"><pre class="prism-code language-js codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line"><span class="token keyword module">import</span><span class="token plain"> </span><span class="token imports">tseslint</span><span class="token plain"> </span><span class="token keyword module">from</span><span class="token plain"> </span><span class="token string">'typescript-eslint'</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token keyword module">export</span><span class="token plain"> </span><span class="token keyword module">default</span><span class="token plain"> tseslint</span><span class="token punctuation">.</span><span class="token method function property-access">config</span><span class="token punctuation">(</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  eslint</span><span class="token punctuation">.</span><span class="token property-access">configs</span><span class="token punctuation">.</span><span class="token property-access">recommended</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token spread operator">...</span><span class="token plain">tseslint</span><span class="token punctuation">.</span><span class="token property-access">configs</span><span class="token punctuation">.</span><span class="token property-access">recommendedTypeChecked</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">    </span><span class="token literal-property property">languageOptions</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">      </span><span class="token literal-property property">parserOptions</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">        </span><span class="token literal-property property">projectService</span><span class="token operator">:</span><span class="token plain"> </span><span class="token boolean">true</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">        </span><span class="token literal-property property">tsconfigRootDir</span><span class="token operator">:</span><span class="token plain"> </span><span class="token keyword module">import</span><span class="token punctuation">.</span><span class="token property-access">meta</span><span class="token punctuation">.</span><span class="token property-access">dirname</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">      </span><span class="token punctuation">}</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">    </span><span class="token punctuation">}</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token punctuation">}</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token punctuation">)</span><span class="token punctuation">;</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>typescript-eslint will then use TypeScript APIs behind-the-scenes, to, for each file being linted:</p>
<ol>
<li>Determine the appropriate TSConfig dictating how to generate that file's type information</li>
<li>Make APIs available to lint rules to retrieve type information for the file</li>
</ol>
<p>Lint rules that opt into type information will then be able to use those APIs when linting your code.</p>
<h2 class="anchor anchorWithStickyNavbar_eAos" id="drawbacks-of-typed-linting">Drawbacks of Typed Linting<a href="https://typescript-eslint.io/blog/typed-linting#drawbacks-of-typed-linting" class="hash-link" aria-label="Direct link to Drawbacks of Typed Linting" title="Direct link to Drawbacks of Typed Linting">​</a></h2>
<p>Linting with type information comes with two drawbacks: configuration complexity and a performance penalty.</p>
<p>For configuring typed linting, <a href="https://typescript-eslint.io/packages/parser#projectservice"><code>parserOptions.projectService</code></a> solves configuration difficulties for most projects.
The more manual <a href="https://typescript-eslint.io/packages/parser#projectservice"><code>parserOptions.project</code></a> is also available for more complex project setups.
See <a href="https://typescript-eslint.io/troubleshooting/typed-linting">Troubleshooting &amp; FAQs &gt; Typed Linting</a> for details on common issues.</p>
<p>For performance, it is inevitable that typed linting will slow your linting down to roughly the speed of type checking your project.
Typed lint rules call to the same TypeScript APIs as the command-line <code>tsc</code>.
If linting your project is much slower than running <code>tsc</code> on the same set of files, see <a href="https://typescript-eslint.io/troubleshooting/typed-linting/performance">Troubleshooting &amp; FAQs &gt; Typed Linting &gt; Performance</a>.</p>
<h2 class="anchor anchorWithStickyNavbar_eAos" id="final-thoughts">Final Thoughts<a href="https://typescript-eslint.io/blog/typed-linting#final-thoughts" class="hash-link" aria-label="Direct link to Final Thoughts" title="Direct link to Final Thoughts">​</a></h2>
<p>In our experience, the additional bug catching and features added by typed linting are well worth the costs of configuration and performance.
Typed linting allows lint rules to act with much greater confidence on a wider area of checking, including avoiding unsafe <code>any</code> uses, enforcing proper <code>this</code> scopes, and catching asynchronous code mishaps.</p>
<p>If you haven't yet tried out typed linting using the typescript-eslint rules mentioned in this blog post, we'd strongly recommend going through our <a href="https://typescript-eslint.io/getting-started/typed-linting">Linting with Type Information</a> guide.</p>
<h2 class="anchor anchorWithStickyNavbar_eAos" id="supporting-typescript-eslint">Supporting typescript-eslint<a href="https://typescript-eslint.io/blog/typed-linting#supporting-typescript-eslint" class="hash-link" aria-label="Direct link to Supporting typescript-eslint" title="Direct link to Supporting typescript-eslint">​</a></h2>
<p>If you enjoyed this blog post and/or use typescript-eslint, please consider <a href="https://opencollective.com/typescript-eslint" target="_blank" rel="noopener noreferrer">supporting us on Open Collective</a>. We're a small volunteer team and could use your support to make the ESLint experience on TypeScript great. Thanks! 💖</p>]]></content:encoded>
            <category>types</category>
            <category>type information</category>
            <category>typed linting</category>
        </item>
        <item>
            <title><![CDATA[Announcing typescript-eslint v8]]></title>
            <link>https://typescript-eslint.io/blog/announcing-typescript-eslint-v8</link>
            <guid>https://typescript-eslint.io/blog/announcing-typescript-eslint-v8</guid>
            <pubDate>Wed, 31 Jul 2024 00:00:00 GMT</pubDate>
            <description><![CDATA[Announcing the stable release of typescript-eslint's v8.]]></description>
            <content:encoded><![CDATA[<p><a href="https://typescript-eslint.io/" target="_blank" rel="noopener noreferrer">typescript-eslint</a> is the tooling that enables standard JavaScript tools such as <a href="https://eslint.org/" target="_blank" rel="noopener noreferrer">ESLint</a> and <a href="https://prettier.io/" target="_blank" rel="noopener noreferrer">Prettier</a> 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.
And now, we're excited to say that typescript-eslint v8 is released as stable! 🎉</p>
<p>We'd previously blogged about v8 in <a href="https://typescript-eslint.io/blog/announcing-typescript-eslint-v8-beta">Announcing typescript-eslint v8 Beta</a>.
This blog post contains much of the same information as that one, and includes the list of steps you'll need to take to upgrade.</p>
<h2 class="anchor anchorWithStickyNavbar_eAos" id="trying-out-v8">Trying Out v8<a href="https://typescript-eslint.io/blog/announcing-typescript-eslint-v8#trying-out-v8" class="hash-link" aria-label="Direct link to Trying Out v8" title="Direct link to Trying Out v8">​</a></h2>
<p>Whether you're new to linting your TypeScript code or a returning user, please do upgrade to the latest major version of typescript-eslint!
V8 comes with a suite of quality-of-life improvements we think you'll appreciate.</p>
<h3 class="anchor anchorWithStickyNavbar_eAos" id="as-a-new-user">As A New User<a href="https://typescript-eslint.io/blog/announcing-typescript-eslint-v8#as-a-new-user" class="hash-link" aria-label="Direct link to As A New User" title="Direct link to As A New User">​</a></h3>
<p>If you don't yet use typescript-eslint, you can go through our <a href="https://typescript-eslint.io/getting-started">configuration steps on the v8 <em>Getting Started</em> docs</a>.
It'll walk you through setting up typescript-eslint in a project.</p>
<h3 class="anchor anchorWithStickyNavbar_eAos" id="as-an-existing-user">As An Existing User<a href="https://typescript-eslint.io/blog/announcing-typescript-eslint-v8#as-an-existing-user" class="hash-link" aria-label="Direct link to As An Existing User" title="Direct link to As An Existing User">​</a></h3>
<p>If you already use typescript-eslint, you'll need to first replace your package's previous versions with <code>@8</code>:</p>
<div class="tabs-container tabList_hoTN"><ul role="tablist" aria-orientation="horizontal" class="tabs"><li role="tab" tabindex="0" aria-selected="true" class="tabs__item tabItem_dW3K tabs__item--active">Flat Config</li><li role="tab" tabindex="-1" aria-selected="false" class="tabs__item tabItem_dW3K">Legacy Config</li></ul><div class="margin-top--md"><div role="tabpanel" class="tabItem_PzSZ"><div class="language-shell codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockContent_m3Ux"><pre class="prism-code language-shell codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line"><span class="token function">npm</span><span class="token plain"> i typescript-eslint@8 --save-dev</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div></div><div role="tabpanel" class="tabItem_PzSZ" hidden=""><div class="language-shell codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockContent_m3Ux"><pre class="prism-code language-shell codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line"><span class="token function">npm</span><span class="token plain"> i @typescript-eslint/eslint-plugin@8 @typescript-eslint/parser@8 --save-dev</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div></div></div></div>
<p>We highly recommend then basing your ESLint configuration on the reworked typescript-eslint <a href="https://typescript-eslint.io/users/configs">recommended configurations</a> — especially if it's been a while since you've reworked your linter config.</p>
<h2 class="anchor anchorWithStickyNavbar_eAos" id="user-facing-changes">User-Facing Changes<a href="https://typescript-eslint.io/blog/announcing-typescript-eslint-v8#user-facing-changes" class="hash-link" aria-label="Direct link to User-Facing Changes" title="Direct link to User-Facing Changes">​</a></h2>
<p>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 v7 to v8.</p>
<h3 class="anchor anchorWithStickyNavbar_eAos" id="eslint-v9-support">ESLint v9 Support<a href="https://typescript-eslint.io/blog/announcing-typescript-eslint-v8#eslint-v9-support" class="hash-link" aria-label="Direct link to ESLint v9 Support" title="Direct link to ESLint v9 Support">​</a></h3>
<p>typescript-eslint v8 ships with full support for ESLint v9.</p>
<p>typescript-eslint v7 was our first version that supported ESLint's <a href="https://eslint.org/docs/latest/use/configure/configuration-files" target="_blank" rel="noopener noreferrer">new "flat" config file format</a>, which was already available in ESLint v8.
ESLint v9 still supports ESLint's <a href="https://eslint.org/docs/latest/use/configure/configuration-files-deprecated" target="_blank" rel="noopener noreferrer">older legacy config file format</a> so our tooling does as well.
However, ESLint v9 also includes a set of breaking changes that we added support for in typescript-eslint v8.
See the <a href="https://eslint.org/blog/2024/04/eslint-v9.0.0-released" target="_blank" rel="noopener noreferrer">ESLint v9 release blog post</a> for more details.</p>
<h3 class="anchor anchorWithStickyNavbar_eAos" id="project-service">Project Service<a href="https://typescript-eslint.io/blog/announcing-typescript-eslint-v8#project-service" class="hash-link" aria-label="Direct link to Project Service" title="Direct link to Project Service">​</a></h3>
<p>The biggest new feature added in this version is the stability of our new "project service".
In short, the project service is a new way to enable <a href="https://typescript-eslint.io/getting-started/typed-linting">typed linting</a> that is generally <em>easier to configure</em> and <em>faster at runtime</em> than our previous offerings.
It's been experimentally available since v6.1.0 under the name <code>EXPERIMENTAL_useProjectService</code>; now, we've renamed it to <code>projectService</code>.</p>
<p>You can use the new project service in your configuration instead of the previous <code>parserOptions.project</code>:</p>
<div class="language-js codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockTitle_P25_">eslint.config.mjs</div><div class="codeBlockContent_m3Ux"><pre class="prism-code language-js codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line"><span class="token keyword module">import</span><span class="token plain"> </span><span class="token imports">eslint</span><span class="token plain"> </span><span class="token keyword module">from</span><span class="token plain"> </span><span class="token string">'@eslint/js'</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token keyword module">import</span><span class="token plain"> </span><span class="token imports">tseslint</span><span class="token plain"> </span><span class="token keyword module">from</span><span class="token plain"> </span><span class="token string">'typescript-eslint'</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token keyword module">export</span><span class="token plain"> </span><span class="token keyword module">default</span><span class="token plain"> tseslint</span><span class="token punctuation">.</span><span class="token method function property-access">config</span><span class="token punctuation">(</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  eslint</span><span class="token punctuation">.</span><span class="token property-access">configs</span><span class="token punctuation">.</span><span class="token property-access">recommended</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token spread operator">...</span><span class="token plain">tseslint</span><span class="token punctuation">.</span><span class="token property-access">configs</span><span class="token punctuation">.</span><span class="token property-access">recommendedTypeChecked</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">    </span><span class="token literal-property property">languageOptions</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">      </span><span class="token literal-property property">parserOptions</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line code-block-removed-line"><span class="token plain">        </span><span class="token literal-property property">project</span><span class="token operator">:</span><span class="token plain"> </span><span class="token boolean">true</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line code-block-added-line"><span class="token plain">        </span><span class="token literal-property property">projectService</span><span class="token operator">:</span><span class="token plain"> </span><span class="token boolean">true</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">        </span><span class="token literal-property property">tsconfigRootDir</span><span class="token operator">:</span><span class="token plain"> </span><span class="token keyword module">import</span><span class="token punctuation">.</span><span class="token property-access">meta</span><span class="token punctuation">.</span><span class="token property-access">dirname</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">      </span><span class="token punctuation">}</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">    </span><span class="token punctuation">}</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token punctuation">}</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token punctuation">)</span><span class="token punctuation">;</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>The project service will automatically find the closest <code>tsconfig.json</code> for each file (like <code>project: true</code>).
It also allows enabling typed linting for files not explicitly included in a <code>tsconfig.json</code>.
This should remove the need for custom <code>tsconfig.eslint.json</code> files to lint files like <code>eslint.config.mjs</code>!</p>
<p>Typed linting for out-of-project files can be done by specifying two properties of a <code>parserOptions.projectService</code> object:</p>
<ul>
<li><code>allowDefaultProject</code>: a glob of a small number of out-of-project files to enable a slower default project on</li>
<li><code>defaultProject</code>: path to a TypeScript configuration file to use for the slower default project</li>
</ul>
<div class="language-js codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockTitle_P25_">eslint.config.mjs</div><div class="codeBlockContent_m3Ux"><pre class="prism-code language-js codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line"><span class="token keyword module">import</span><span class="token plain"> </span><span class="token imports">eslint</span><span class="token plain"> </span><span class="token keyword module">from</span><span class="token plain"> </span><span class="token string">'@eslint/js'</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token keyword module">import</span><span class="token plain"> </span><span class="token imports">tseslint</span><span class="token plain"> </span><span class="token keyword module">from</span><span class="token plain"> </span><span class="token string">'typescript-eslint'</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token keyword module">export</span><span class="token plain"> </span><span class="token keyword module">default</span><span class="token plain"> tseslint</span><span class="token punctuation">.</span><span class="token method function property-access">config</span><span class="token punctuation">(</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  eslint</span><span class="token punctuation">.</span><span class="token property-access">configs</span><span class="token punctuation">.</span><span class="token property-access">recommended</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token spread operator">...</span><span class="token plain">tseslint</span><span class="token punctuation">.</span><span class="token property-access">configs</span><span class="token punctuation">.</span><span class="token property-access">recommendedTypeChecked</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">    </span><span class="token literal-property property">languageOptions</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">      </span><span class="token literal-property property">parserOptions</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line code-block-removed-line"><span class="token plain">        </span><span class="token literal-property property">project</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation">[</span><span class="token string">'packages/*/tsconfig.json'</span><span class="token punctuation">,</span><span class="token plain"> </span><span class="token string">'tsconfig.eslint.json'</span><span class="token punctuation">]</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line code-block-added-line"><span class="token plain">        </span><span class="token literal-property property">projectService</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line code-block-added-line"><span class="token plain">          </span><span class="token literal-property property">allowDefaultProject</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation">[</span><span class="token string">'*.js'</span><span class="token punctuation">]</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line code-block-added-line"><span class="token plain">          </span><span class="token literal-property property">defaultProject</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'tsconfig.json'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line code-block-added-line"><span class="token plain">        </span><span class="token punctuation">}</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">        </span><span class="token literal-property property">tsconfigRootDir</span><span class="token operator">:</span><span class="token plain"> </span><span class="token keyword module">import</span><span class="token punctuation">.</span><span class="token property-access">meta</span><span class="token punctuation">.</span><span class="token property-access">dirname</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">      </span><span class="token punctuation">}</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">    </span><span class="token punctuation">}</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token punctuation">}</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token punctuation">)</span><span class="token punctuation">;</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Internally, the project service uses the same TypeScript APIs that editors such as VS Code use.
Doing so should make it harder to accidentally configure different type information for ESLint than what you see in day-to-day editing.</p>
<p>We're thrilled to have the project service option promoted to stable in v8.
We'll soon release a <a href="https://github.com/typescript-eslint/typescript-eslint/pull/8031" target="_blank" rel="noopener noreferrer">dedicated <code>parserOptions</code> blog post</a> walking through the new option in more details.
🚀</p>
<h3 class="anchor anchorWithStickyNavbar_eAos" id="updated-configuration-rules">Updated Configuration Rules<a href="https://typescript-eslint.io/blog/announcing-typescript-eslint-v8#updated-configuration-rules" class="hash-link" aria-label="Direct link to Updated Configuration Rules" title="Direct link to Updated Configuration Rules">​</a></h3>
<p>Every new major version of typescript-eslint comes with changes to which rules are enabled in the preset configurations and with which options.
See the table in <a href="https://github.com/typescript-eslint/typescript-eslint/discussions/8914" target="_blank" rel="noopener noreferrer">Changes to configurations for 8.0.0</a> for more context on the changes.</p>
<p>Please do try out the new rule configurations presets and let us know in that discussion!</p>
<div class="theme-admonition theme-admonition-tip admonition_pzuZ alert alert--success"><div class="admonitionHeading_uJho"><span class="admonitionIcon_vMH2"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>tip</div><div class="admonitionContent_gazR"><p>If your ESLint configuration contains many <code>rules</code> configurations, we suggest the following strategy to start anew:</p><ol>
<li>Remove all your rules configurations</li>
<li>Extend from the preset configs that make sense for you</li>
<li>Run ESLint on your project</li>
<li>In your ESLint configuration, turn off any rules creating errors that don't make sense for your project — with comments explaining why</li>
<li>In your ESLint configuration and/or with inline <code>eslint-disable</code> comments, turn off / downgrade to "warn" any rules creating too many errors for you to fix — with <em>"TODO"</em> comments linking to tracking issues/tickets to re-enable them</li>
</ol></div></div>
<details class="details_JN11 alert alert--info details_tgxR" data-collapsed="true"><summary>Diff patch from v7 to v8 for <em><code>recommended</code></em></summary><div><div class="collapsibleContent_BLuU"><div class="language-diff codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockContent_m3Ux"><pre class="prism-code language-diff codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line"><span class="token plain">{</span><br></span><span class="token-line"><span class="token plain"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/ban-ts-comment': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token deleted-sign deleted prefix deleted">-</span><span class="token deleted-sign deleted line">  '@typescript-eslint/ban-types': '...',</span><br></span><span class="token-line"><span class="token deleted-sign deleted line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  'no-array-constructor': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-array-constructor': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-duplicate-enum-values': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token inserted-sign inserted prefix inserted">+</span><span class="token inserted-sign inserted line">  '@typescript-eslint/no-empty-object-type': '...',</span><br></span><span class="token-line"><span class="token inserted-sign inserted line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-explicit-any': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-extra-non-null-assertion': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token deleted-sign deleted prefix deleted">-</span><span class="token deleted-sign deleted line">  'no-loss-of-precision': '...',</span><br></span><span class="token-line"><span class="token deleted-sign deleted line"></span><span class="token deleted-sign deleted prefix deleted">-</span><span class="token deleted-sign deleted line">  '@typescript-eslint/no-loss-of-precision': '...',</span><br></span><span class="token-line"><span class="token deleted-sign deleted line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-misused-new': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-namespace': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-non-null-asserted-optional-chain': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token inserted-sign inserted prefix inserted">+</span><span class="token inserted-sign inserted line">  '@typescript-eslint/no-require-imports': '...',</span><br></span><span class="token-line"><span class="token inserted-sign inserted line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-this-alias': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-unnecessary-type-constraint': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-unsafe-declaration-merging': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token inserted-sign inserted prefix inserted">+</span><span class="token inserted-sign inserted line">  '@typescript-eslint/no-unsafe-function-type': '...',</span><br></span><span class="token-line"><span class="token inserted-sign inserted line"></span><span class="token inserted-sign inserted prefix inserted">+</span><span class="token inserted-sign inserted line">  'no-unused-expressions': '...',</span><br></span><span class="token-line"><span class="token inserted-sign inserted line"></span><span class="token inserted-sign inserted prefix inserted">+</span><span class="token inserted-sign inserted line">  '@typescript-eslint/no-unused-expressions': '...',</span><br></span><span class="token-line"><span class="token inserted-sign inserted line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  'no-unused-vars': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-unused-vars': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token deleted-sign deleted prefix deleted">-</span><span class="token deleted-sign deleted line">  '@typescript-eslint/no-var-requires': '...',</span><br></span><span class="token-line"><span class="token deleted-sign deleted line"></span><span class="token inserted-sign inserted prefix inserted">+</span><span class="token inserted-sign inserted line">  '@typescript-eslint/no-wrapper-object-types': '...',</span><br></span><span class="token-line"><span class="token inserted-sign inserted line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/prefer-as-const': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token inserted-sign inserted prefix inserted">+</span><span class="token inserted-sign inserted line">  '@typescript-eslint/prefer-namespace-keyword': '...',</span><br></span><span class="token-line"><span class="token inserted-sign inserted line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/triple-slash-reference': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token plain">}</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div></div></div></details>
<details class="details_JN11 alert alert--info details_tgxR" data-collapsed="true"><summary>Diff patch from v7 to v8 for <em><code>recommended-type-checked</code></em></summary><div><div class="collapsibleContent_BLuU"><div class="language-diff codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockContent_m3Ux"><pre class="prism-code language-diff codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line"><span class="token plain">{</span><br></span><span class="token-line"><span class="token plain"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/await-thenable': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/ban-ts-comment': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token deleted-sign deleted prefix deleted">-</span><span class="token deleted-sign deleted line">  '@typescript-eslint/ban-types': '...',</span><br></span><span class="token-line"><span class="token deleted-sign deleted line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  'no-array-constructor': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-array-constructor': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token inserted-sign inserted prefix inserted">+</span><span class="token inserted-sign inserted line">  '@typescript-eslint/no-array-delete': '...',</span><br></span><span class="token-line"><span class="token inserted-sign inserted line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-base-to-string': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-duplicate-enum-values': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-duplicate-type-constituents': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token inserted-sign inserted prefix inserted">+</span><span class="token inserted-sign inserted line">  '@typescript-eslint/no-empty-object-type': '...',</span><br></span><span class="token-line"><span class="token inserted-sign inserted line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-explicit-any': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-extra-non-null-assertion': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-floating-promises': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-for-in-array': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  'no-implied-eval': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-implied-eval': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token deleted-sign deleted prefix deleted">-</span><span class="token deleted-sign deleted line">  'no-loss-of-precision': '...',</span><br></span><span class="token-line"><span class="token deleted-sign deleted line"></span><span class="token deleted-sign deleted prefix deleted">-</span><span class="token deleted-sign deleted line">  '@typescript-eslint/no-loss-of-precision': '...',</span><br></span><span class="token-line"><span class="token deleted-sign deleted line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-misused-new': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-misused-promises': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-namespace': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-non-null-asserted-optional-chain': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-redundant-type-constituents': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token inserted-sign inserted prefix inserted">+</span><span class="token inserted-sign inserted line">  '@typescript-eslint/no-require-imports': '...',</span><br></span><span class="token-line"><span class="token inserted-sign inserted line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-this-alias': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token inserted-sign inserted prefix inserted">+</span><span class="token inserted-sign inserted line">  'no-throw-literal': '...',</span><br></span><span class="token-line"><span class="token inserted-sign inserted line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-unnecessary-type-assertion': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-unnecessary-type-constraint': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-unsafe-argument': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-unsafe-assignment': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-unsafe-call': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-unsafe-declaration-merging': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-unsafe-enum-comparison': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token inserted-sign inserted prefix inserted">+</span><span class="token inserted-sign inserted line">  '@typescript-eslint/no-unsafe-function-type': '...',</span><br></span><span class="token-line"><span class="token inserted-sign inserted line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-unsafe-member-access': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-unsafe-return': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token inserted-sign inserted prefix inserted">+</span><span class="token inserted-sign inserted line">  '@typescript-eslint/no-unsafe-unary-minus': '...',</span><br></span><span class="token-line"><span class="token inserted-sign inserted line"></span><span class="token inserted-sign inserted prefix inserted">+</span><span class="token inserted-sign inserted line">  'no-unused-expressions': '...',</span><br></span><span class="token-line"><span class="token inserted-sign inserted line"></span><span class="token inserted-sign inserted prefix inserted">+</span><span class="token inserted-sign inserted line">  '@typescript-eslint/no-unused-expressions': '...',</span><br></span><span class="token-line"><span class="token inserted-sign inserted line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  'no-unused-vars': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-unused-vars': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token deleted-sign deleted prefix deleted">-</span><span class="token deleted-sign deleted line">  '@typescript-eslint/no-var-requires': '...',</span><br></span><span class="token-line"><span class="token deleted-sign deleted line"></span><span class="token inserted-sign inserted prefix inserted">+</span><span class="token inserted-sign inserted line">  '@typescript-eslint/no-wrapper-object-types': '...',</span><br></span><span class="token-line"><span class="token inserted-sign inserted line"></span><span class="token inserted-sign inserted prefix inserted">+</span><span class="token inserted-sign inserted line">  '@typescript-eslint/only-throw-error': '...',</span><br></span><span class="token-line"><span class="token inserted-sign inserted line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/prefer-as-const': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token inserted-sign inserted prefix inserted">+</span><span class="token inserted-sign inserted line">  '@typescript-eslint/prefer-namespace-keyword': '...',</span><br></span><span class="token-line"><span class="token inserted-sign inserted line"></span><span class="token inserted-sign inserted prefix inserted">+</span><span class="token inserted-sign inserted line">  'prefer-promise-reject-errors': '...',</span><br></span><span class="token-line"><span class="token inserted-sign inserted line"></span><span class="token inserted-sign inserted prefix inserted">+</span><span class="token inserted-sign inserted line">  '@typescript-eslint/prefer-promise-reject-errors': '...',</span><br></span><span class="token-line"><span class="token inserted-sign inserted line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  'require-await': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/require-await': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/restrict-plus-operands': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/restrict-template-expressions': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/triple-slash-reference': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/unbound-method': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token plain">}</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div></div></div></details>
<details class="details_JN11 alert alert--info details_tgxR" data-collapsed="true"><summary>Diff patch from v7 to v8 for <em><code>strict</code></em></summary><div><div class="collapsibleContent_BLuU"><div class="language-diff codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockContent_m3Ux"><pre class="prism-code language-diff codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line"><span class="token plain">{</span><br></span><span class="token-line"><span class="token plain"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/ban-ts-comment': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token deleted-sign deleted prefix deleted">-</span><span class="token deleted-sign deleted line">  '@typescript-eslint/ban-types': '...',</span><br></span><span class="token-line"><span class="token deleted-sign deleted line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  'no-array-constructor': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-array-constructor': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-duplicate-enum-values': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-dynamic-delete': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token inserted-sign inserted prefix inserted">+</span><span class="token inserted-sign inserted line">  '@typescript-eslint/no-empty-object-type': '...',</span><br></span><span class="token-line"><span class="token inserted-sign inserted line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-explicit-any': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-extra-non-null-assertion': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-extraneous-class': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-invalid-void-type': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token deleted-sign deleted prefix deleted">-</span><span class="token deleted-sign deleted line">  'no-loss-of-precision': '...',</span><br></span><span class="token-line"><span class="token deleted-sign deleted line"></span><span class="token deleted-sign deleted prefix deleted">-</span><span class="token deleted-sign deleted line">  '@typescript-eslint/no-loss-of-precision': '...',</span><br></span><span class="token-line"><span class="token deleted-sign deleted line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-misused-new': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-namespace': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-non-null-asserted-nullish-coalescing': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-non-null-asserted-optional-chain': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-non-null-assertion': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token inserted-sign inserted prefix inserted">+</span><span class="token inserted-sign inserted line">  '@typescript-eslint/no-require-imports': '...',</span><br></span><span class="token-line"><span class="token inserted-sign inserted line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-this-alias': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-unnecessary-type-constraint': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-unsafe-declaration-merging': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token inserted-sign inserted prefix inserted">+</span><span class="token inserted-sign inserted line">  '@typescript-eslint/no-unsafe-function-type': '...',</span><br></span><span class="token-line"><span class="token inserted-sign inserted line"></span><span class="token inserted-sign inserted prefix inserted">+</span><span class="token inserted-sign inserted line">  'no-unused-expressions': '...',</span><br></span><span class="token-line"><span class="token inserted-sign inserted line"></span><span class="token inserted-sign inserted prefix inserted">+</span><span class="token inserted-sign inserted line">  '@typescript-eslint/no-unused-expressions': '...',</span><br></span><span class="token-line"><span class="token inserted-sign inserted line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  'no-unused-vars': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-unused-vars': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  'no-useless-constructor': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-useless-constructor': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token deleted-sign deleted prefix deleted">-</span><span class="token deleted-sign deleted line">  '@typescript-eslint/no-var-requires': '...',</span><br></span><span class="token-line"><span class="token deleted-sign deleted line"></span><span class="token inserted-sign inserted prefix inserted">+</span><span class="token inserted-sign inserted line">  '@typescript-eslint/no-wrapper-object-types': '...',</span><br></span><span class="token-line"><span class="token inserted-sign inserted line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/prefer-as-const': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/prefer-literal-enum-member': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token inserted-sign inserted prefix inserted">+</span><span class="token inserted-sign inserted line">  '@typescript-eslint/prefer-namespace-keyword': '...',</span><br></span><span class="token-line"><span class="token inserted-sign inserted line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/triple-slash-reference': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/unified-signatures': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token plain">}</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div></div></div></details>
<details class="details_JN11 alert alert--info details_tgxR" data-collapsed="true"><summary>Diff patch from v7 to v8 for <em><code>strict-type-checked</code></em></summary><div><div class="collapsibleContent_BLuU"><div class="language-diff codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockContent_m3Ux"><pre class="prism-code language-diff codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line"><span class="token plain">{</span><br></span><span class="token-line"><span class="token plain"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/await-thenable': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/ban-ts-comment': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token deleted-sign deleted prefix deleted">-</span><span class="token deleted-sign deleted line">  '@typescript-eslint/ban-types': '...',</span><br></span><span class="token-line"><span class="token deleted-sign deleted line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  'no-array-constructor': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-array-constructor': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-array-delete': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-base-to-string': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-confusing-void-expression': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-duplicate-enum-values': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-duplicate-type-constituents': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-dynamic-delete': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token inserted-sign inserted prefix inserted">+</span><span class="token inserted-sign inserted line">  '@typescript-eslint/no-empty-object-type': '...',</span><br></span><span class="token-line"><span class="token inserted-sign inserted line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-explicit-any': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-extra-non-null-assertion': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-extraneous-class': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-floating-promises': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-for-in-array': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  'no-implied-eval': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-implied-eval': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-invalid-void-type': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token deleted-sign deleted prefix deleted">-</span><span class="token deleted-sign deleted line">  'no-loss-of-precision': '...',</span><br></span><span class="token-line"><span class="token deleted-sign deleted line"></span><span class="token deleted-sign deleted prefix deleted">-</span><span class="token deleted-sign deleted line">  '@typescript-eslint/no-loss-of-precision': '...',</span><br></span><span class="token-line"><span class="token deleted-sign deleted line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-meaningless-void-operator': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-misused-new': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-misused-promises': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-mixed-enums': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-namespace': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-non-null-asserted-nullish-coalescing': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-non-null-asserted-optional-chain': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-non-null-assertion': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-redundant-type-constituents': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token inserted-sign inserted prefix inserted">+</span><span class="token inserted-sign inserted line">  '@typescript-eslint/no-require-imports': '...',</span><br></span><span class="token-line"><span class="token inserted-sign inserted line"></span><span class="token inserted-sign inserted prefix inserted">+</span><span class="token inserted-sign inserted line">  'no-return-await': '...',</span><br></span><span class="token-line"><span class="token inserted-sign inserted line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-this-alias': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  'no-throw-literal': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-unnecessary-boolean-literal-compare': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-unnecessary-condition': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-unnecessary-template-expression': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-unnecessary-type-arguments': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-unnecessary-type-assertion': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-unnecessary-type-constraint': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token inserted-sign inserted prefix inserted">+</span><span class="token inserted-sign inserted line">  '@typescript-eslint/no-unnecessary-type-parameters': '...',</span><br></span><span class="token-line"><span class="token inserted-sign inserted line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-unsafe-argument': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-unsafe-assignment': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-unsafe-call': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-unsafe-declaration-merging': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-unsafe-enum-comparison': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token inserted-sign inserted prefix inserted">+</span><span class="token inserted-sign inserted line">  '@typescript-eslint/no-unsafe-function-type': '...',</span><br></span><span class="token-line"><span class="token inserted-sign inserted line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-unsafe-member-access': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-unsafe-return': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token inserted-sign inserted prefix inserted">+</span><span class="token inserted-sign inserted line">  '@typescript-eslint/no-unsafe-unary-minus': '...',</span><br></span><span class="token-line"><span class="token inserted-sign inserted line"></span><span class="token inserted-sign inserted prefix inserted">+</span><span class="token inserted-sign inserted line">  'no-unused-expressions': '...',</span><br></span><span class="token-line"><span class="token inserted-sign inserted line"></span><span class="token inserted-sign inserted prefix inserted">+</span><span class="token inserted-sign inserted line">  '@typescript-eslint/no-unused-expressions': '...',</span><br></span><span class="token-line"><span class="token inserted-sign inserted line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  'no-unused-vars': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-unused-vars': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  'no-useless-constructor': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-useless-constructor': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token deleted-sign deleted prefix deleted">-</span><span class="token deleted-sign deleted line">  '@typescript-eslint/no-var-requires': '...',</span><br></span><span class="token-line"><span class="token deleted-sign deleted line"></span><span class="token inserted-sign inserted prefix inserted">+</span><span class="token inserted-sign inserted line">  '@typescript-eslint/no-wrapper-object-types': '...',</span><br></span><span class="token-line"><span class="token inserted-sign inserted line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/only-throw-error': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/prefer-as-const': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token deleted-sign deleted prefix deleted">-</span><span class="token deleted-sign deleted line">  '@typescript-eslint/prefer-includes': '...',</span><br></span><span class="token-line"><span class="token deleted-sign deleted line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/prefer-literal-enum-member': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token inserted-sign inserted prefix inserted">+</span><span class="token inserted-sign inserted line">  '@typescript-eslint/prefer-namespace-keyword': '...',</span><br></span><span class="token-line"><span class="token inserted-sign inserted line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  'prefer-promise-reject-errors': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/prefer-promise-reject-errors': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/prefer-reduce-type-parameter': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/prefer-return-this-type': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  'require-await': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/require-await': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/restrict-plus-operands': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/restrict-template-expressions': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token inserted-sign inserted prefix inserted">+</span><span class="token inserted-sign inserted line">  '@typescript-eslint/return-await': '...',</span><br></span><span class="token-line"><span class="token inserted-sign inserted line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/triple-slash-reference': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/unbound-method': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/unified-signatures': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/use-unknown-in-catch-callback-variable': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token plain">}</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div></div></div></details>
<details class="details_JN11 alert alert--info details_tgxR" data-collapsed="true"><summary>Diff patch from v7 to v8 for <em><code>stylistic</code></em></summary><div><div class="collapsibleContent_BLuU"><div class="language-diff codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockContent_m3Ux"><pre class="prism-code language-diff codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line"><span class="token plain">{</span><br></span><span class="token-line"><span class="token plain"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/adjacent-overload-signatures': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/array-type': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/ban-tslint-comment': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/class-literal-property-style': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/consistent-generic-constructors': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/consistent-indexed-object-style': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/consistent-type-assertions': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/consistent-type-definitions': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-confusing-non-null-assertion': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  'no-empty-function': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-empty-function': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token deleted-sign deleted prefix deleted">-</span><span class="token deleted-sign deleted line">  '@typescript-eslint/no-empty-interface': '...',</span><br></span><span class="token-line"><span class="token deleted-sign deleted line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-inferrable-types': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/prefer-for-of': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/prefer-function-type': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token deleted-sign deleted prefix deleted">-</span><span class="token deleted-sign deleted line">  '@typescript-eslint/prefer-namespace-keyword': '...',</span><br></span><span class="token-line"><span class="token deleted-sign deleted line"></span><span class="token plain">}</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div></div></div></details>
<details class="details_JN11 alert alert--info details_tgxR" data-collapsed="true"><summary>Diff patch from v7 to v8 for <em><code>stylistic-type-checked</code></em></summary><div><div class="collapsibleContent_BLuU"><div class="language-diff codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockContent_m3Ux"><pre class="prism-code language-diff codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line"><span class="token plain">{</span><br></span><span class="token-line"><span class="token plain"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/adjacent-overload-signatures': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/array-type': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/ban-tslint-comment': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/class-literal-property-style': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/consistent-generic-constructors': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/consistent-indexed-object-style': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/consistent-type-assertions': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/consistent-type-definitions': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  'dot-notation': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/dot-notation': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-confusing-non-null-assertion': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  'no-empty-function': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-empty-function': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token deleted-sign deleted prefix deleted">-</span><span class="token deleted-sign deleted line">  '@typescript-eslint/no-empty-interface': '...',</span><br></span><span class="token-line"><span class="token deleted-sign deleted line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-inferrable-types': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/non-nullable-type-assertion-style': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token inserted-sign inserted prefix inserted">+</span><span class="token inserted-sign inserted line">  '@typescript-eslint/prefer-find': '...',</span><br></span><span class="token-line"><span class="token inserted-sign inserted line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/prefer-for-of': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/prefer-function-type': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token inserted-sign inserted prefix inserted">+</span><span class="token inserted-sign inserted line">  '@typescript-eslint/prefer-includes': '...',</span><br></span><span class="token-line"><span class="token inserted-sign inserted line"></span><span class="token deleted-sign deleted prefix deleted">-</span><span class="token deleted-sign deleted line">  '@typescript-eslint/prefer-namespace-keyword': '...',</span><br></span><span class="token-line"><span class="token deleted-sign deleted line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/prefer-nullish-coalescing': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/prefer-optional-chain': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token inserted-sign inserted prefix inserted">+</span><span class="token inserted-sign inserted line">  '@typescript-eslint/prefer-regexp-exec': '...',</span><br></span><span class="token-line"><span class="token inserted-sign inserted line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/prefer-string-starts-ends-with': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token plain">}</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div></div></div></details>
<h3 class="anchor anchorWithStickyNavbar_eAos" id="rule-breaking-changes">Rule Breaking Changes<a href="https://typescript-eslint.io/blog/announcing-typescript-eslint-v8#rule-breaking-changes" class="hash-link" aria-label="Direct link to Rule Breaking Changes" title="Direct link to Rule Breaking Changes">​</a></h3>
<p>Several rules are changed in significant enough ways to be considered breaking changes:</p>
<ul>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/issues/8333" target="_blank" rel="noopener noreferrer">Rules: Deprecate prefer-ts-expect-error in favor of ban-ts-comment</a>
<ul>
<li>If you have <a href="https://typescript-eslint.io/rules/prefer-ts-expect-error"><code>@typescript-eslint/prefer-ts-expect-error</code></a> manually enabled, remove that, and instead either use a <a href="https://typescript-eslint.io/users/configs">recommended config</a> or manually enable <a href="https://typescript-eslint.io/rules/ban-ts-comment"><code>@typescript-eslint/ban-ts-comment</code></a>.</li>
</ul>
</li>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/pull/8334" target="_blank" rel="noopener noreferrer">chore(eslint-plugin): deprecate no-var-requires in favor of no-require-imports</a>
<ul>
<li>If you have <a href="https://typescript-eslint.io/rules/no-var-requires"><code>@typescript-eslint/no-var-requires</code></a> manually enabled, remove that, and instead either use a <a href="https://typescript-eslint.io/users/configs">recommended config</a> or manually enable <a href="https://typescript-eslint.io/rules/no-require-imports"><code>@typescript-eslint/no-require-imports</code></a>.</li>
</ul>
</li>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/issues/9083" target="_blank" rel="noopener noreferrer">feat(eslint-plugin): remove deprecated no-throw-literal rule</a>
<ul>
<li>If you have <a href="https://typescript-eslint.io/rules/no-throw-literal" target="_blank" rel="noopener noreferrer"><code>@typescript-eslint/no-throw-literal</code></a> manually enabled, remove that, and instead either use a <a href="https://typescript-eslint.io/users/configs">recommended config</a> or manually enable <a href="https://typescript-eslint.io/rules/only-throw-error"><code>@typescript-eslint/only-throw-error</code></a>.</li>
</ul>
</li>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/pull/8821" target="_blank" rel="noopener noreferrer">feat(eslint-plugin): [no-useless-template-literals] rename to no-useless-template-expression (deprecate no-useless-template-literals)</a> and <a href="https://github.com/typescript-eslint/typescript-eslint/pull/9174" target="_blank" rel="noopener noreferrer">fix: no-useless-template-expression -&gt; no-unnecessary-template-expression</a>
<ul>
<li>Find-and-replace text from <code>no-useless-template-literals</code> to <code>no-unnecessary-template-expression</code></li>
</ul>
</li>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/pull/8832" target="_blank" rel="noopener noreferrer">feat(eslint-plugin): deprecate no-loss-of-precision extension rule</a>
<ul>
<li>If you have <a href="https://typescript-eslint.io/rules/no-loss-of-precision"><code>@typescript-eslint/no-loss-of-precision</code></a> manually enabled, replace it with the base rule <code>no-loss-of-precision</code>.</li>
</ul>
</li>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/pull/8833" target="_blank" rel="noopener noreferrer">feat(eslint-plugin): remove formatting/layout rules</a>
<ul>
<li>If you're using any of the old deprecated formatting rules, see <a href="https://eslint.style/" target="_blank" rel="noopener noreferrer">eslint.style</a> for their new equivalents</li>
</ul>
</li>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/pull/8872" target="_blank" rel="noopener noreferrer">feat(eslint-plugin): [prefer-nullish-coalescing] change ignoreConditionalTests default to true</a>
<ul>
<li>If you want to have the rule check conditional tests, set its <a href="https://typescript-eslint.io/rules/prefer-nullish-coalescing/#ignoreconditionaltests"><code>ignoreConditionalTests</code> option</a> to <code>false</code> in your ESLint config</li>
</ul>
</li>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/pull/8971" target="_blank" rel="noopener noreferrer">feat(eslint-plugin): [no-unused-vars] align catch behavior to ESLint 9</a>
<ul>
<li>If you want <a href="https://typescript-eslint.io/rules/no-unused-vars"><code>@typescript-eslint/no-unused-vars</code></a> to ignore caught errors, enable its <code>caughtErrors</code> option to <code>'none'</code> in your ESLint config</li>
</ul>
</li>
</ul>
<h4 class="anchor anchorWithStickyNavbar_eAos" id="replacement-of-ban-types">Replacement of <code>ban-types</code><a href="https://typescript-eslint.io/blog/announcing-typescript-eslint-v8#replacement-of-ban-types" class="hash-link" aria-label="Direct link to replacement-of-ban-types" title="Direct link to replacement-of-ban-types">​</a></h4>
<p><a href="https://typescript-eslint.io/rules/ban-types" target="_blank" rel="noopener noreferrer"><code>@typescript-eslint/ban-types</code></a> has long been one of the more controversial rules in typescript-eslint.
It served two purposes:</p>
<ul>
<li>Allowing users to ban a configurable list of types from being used in type annotations</li>
<li>Banning confusing or dangerous built-in types such as <code>Function</code> and <code>Number</code></li>
</ul>
<p>Notably, <code>ban-types</code> banned the built-in <code>{}</code> ("empty object") type in TypeScript.
The <code>{}</code> type is a common source of confusion for TypeScript developers because it matches <em>any non-nullable</em> value, including primitives like <code>""</code>.</p>
<p>Banning <code>{}</code> in <code>ban-types</code> was helpful to prevent developers from accidentally using it instead of a more safe type such as <code>object</code>.
On the other hand, there are legitimate uses for <code>{}</code>, and banning it by default was harmful in those cases.</p>
<p>typescript-eslint v8 deletes the <code>ban-types</code> rule and replaces it with several more targeted rules:</p>
<ul>
<li><a href="https://typescript-eslint.io/rules/no-restricted-types"><code>@typescript-eslint/no-restricted-types</code></a> is the new rule for banning a configurable list of type names.
It has no options enabled by default.</li>
<li><a href="https://typescript-eslint.io/rules/no-empty-object-type"><code>@typescript-eslint/no-empty-object-type</code></a> bans the built-in <code>{}</code> type in confusing locations.</li>
<li><a href="https://typescript-eslint.io/rules/no-unsafe-function-type"><code>@typescript-eslint/no-unsafe-function-type</code></a> bans the built-in <code>Function</code> type</li>
<li><a href="https://typescript-eslint.io/rules/no-wrapper-object-types"><code>@typescript-eslint/no-wrapper-object-types</code></a> bans <code>Object</code> and built-in class wrappers such as <code>Number</code>.</li>
</ul>
<p>To migrate to the new rules:</p>
<ul>
<li>If you were disabling the ban on <code>{}</code>, consider enabling <a href="https://typescript-eslint.io/rules/no-empty-object-type"><code>@typescript-eslint/no-empty-object-type</code></a>, as it allows some cases of <code>{}</code> that were previously banned.</li>
<li>If you were banning any configurable types lists, provide a similar configuration to <a href="https://typescript-eslint.io/rules/no-restricted-types"><code>no-restricted-types</code></a>.</li>
<li>If you have <a href="https://typescript-eslint.io/rules/ban-types"><code>@typescript-eslint/ban-types</code></a> manually enabled, it will no longer ban:<!-- -->
<ul>
<li><code>{}</code>: use a <a href="https://typescript-eslint.io/users/configs">recommended config</a> or manually enable <a href="https://typescript-eslint.io/rules/no-empty-object-type"><code>@typescript-eslint/no-empty-object-type</code></a>.</li>
<li><code>Function</code>: use a <a href="https://typescript-eslint.io/users/configs">recommended config</a> or manually enable <a href="https://typescript-eslint.io/rules/no-unsafe-function-type"><code>@typescript-eslint/no-unsafe-function-type</code></a>.</li>
<li><code>Number</code> or other built-in uppercase types: use a <a href="https://typescript-eslint.io/users/configs">recommended config</a> or manually enable <a href="https://typescript-eslint.io/rules/no-wrapper-object-types"><code>@typescript-eslint/no-wrapper-object-types</code></a>.</li>
</ul>
</li>
<li>If you have <a href="https://typescript-eslint.io/rules/no-empty-interface"><code>@typescript-eslint/no-empty-interface</code></a> manually enabled, remove that, and instead either use a <a href="https://typescript-eslint.io/users/configs">recommended config</a> or manually enable <a href="https://typescript-eslint.io/rules/no-empty-object-type"><code>@typescript-eslint/no-empty-object-type</code></a>.</li>
</ul>
<p>For more details, see the issues and pull requests that split apart the <code>ban-types</code> rule:</p>
<ul>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/issues/8700" target="_blank" rel="noopener noreferrer">Enhancement: [ban-types] Split the <!-- --> ban into a separate, better-phrased rule</a></li>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/pull/8977" target="_blank" rel="noopener noreferrer">feat(eslint-plugin): split no-empty-object-type out from ban-types and no-empty-interface</a></li>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/issues/8978" target="_blank" rel="noopener noreferrer">Enhancement: [ban-types] Split into default-less no-restricted-types and more targeted type ban rule(s)</a></li>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/pull/9102" target="_blank" rel="noopener noreferrer">feat(eslint-plugin): replace ban-types with no-restricted-types, no-unsafe-function-type, no-wrapper-object-types</a></li>
</ul>
<h3 class="anchor anchorWithStickyNavbar_eAos" id="tooling-breaking-changes">Tooling Breaking Changes<a href="https://typescript-eslint.io/blog/announcing-typescript-eslint-v8#tooling-breaking-changes" class="hash-link" aria-label="Direct link to Tooling Breaking Changes" title="Direct link to Tooling Breaking Changes">​</a></h3>
<ul>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/pull/8818" target="_blank" rel="noopener noreferrer">fix(typescript-estree): enable dot globs for project by default</a>
<ul>
<li>This will cause any <code>parserOptions.project</code> globs to match dot (<code>.</code>) directories.
If you don't want to match them then use a more specific set of globs, or switch to <code>parserOptions.projectService</code>.</li>
</ul>
</li>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/pull/8834" target="_blank" rel="noopener noreferrer">feat(typescript-estree): remove slow deprecated and isolated programs</a>
<ul>
<li>If you were still using <code>parserOptions.DEPRECATED__createDefaultProgram</code>, switch to <code>parserOptions.projectService</code> <em>(recommended)</em> or <code>parserOptions.project</code>.</li>
</ul>
</li>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/pull/8922" target="_blank" rel="noopener noreferrer">feat(typescript-estree): rename automaticSingleRunInference to disallowAutomaticSingleRunInference</a>
<ul>
<li>We've updated the default to be an opt-out - meaning you no longer need to enable it:<!-- -->
<div class="language-js codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockContent_m3Ux"><pre class="prism-code language-js codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line"><span class="token literal-property property">parserOptions</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line code-block-removed-line"><span class="token plain">  </span><span class="token literal-property property">automaticSingleRunInference</span><span class="token operator">:</span><span class="token plain"> </span><span class="token boolean">true</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token comment">// ...</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token punctuation">}</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
</li>
</ul>
</li>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/pull/8973" target="_blank" rel="noopener noreferrer">chore: bump minimum versions for v8</a>
<ul>
<li>ESLint support range was changed from <code>^8.56.0</code> to <code>^8.57.0</code></li>
<li>Node.js support range was changed from <code>^18.18.0 || &gt;=20.0.0</code> to <code>^18.18.0 || ^20.9.0 || &gt;=21.1.0</code></li>
<li>TypeScript support range was changed from <code>&gt;=4.7.4 &lt;5.5.0</code> to <code>&gt;=4.8.4 &lt;5.5.0</code></li>
</ul>
</li>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/issues/9088" target="_blank" rel="noopener noreferrer">Parser: remove EXPERIMENTAL_useSourceOfProjectReferenceRedirect in favor of project service</a>
<ul>
<li>We now recommend using the new <a href="https://typescript-eslint.io/blog/announcing-typescript-eslint-v8#project-service"><code>parserOptions.projectService</code></a> instead</li>
</ul>
</li>
</ul>
<h2 class="anchor anchorWithStickyNavbar_eAos" id="developer-facing-changes">Developer-Facing Changes<a href="https://typescript-eslint.io/blog/announcing-typescript-eslint-v8#developer-facing-changes" class="hash-link" aria-label="Direct link to Developer-Facing Changes" title="Direct link to Developer-Facing Changes">​</a></h2>
<p>typescript-eslint v8 comes with a suite of cleanups and improvements for developers using its Node.js APIs as well.
If you author any ESLint plugins or other tools that interact with TypeScript syntax, then we recommend you try out typescript-eslint v8 soon.
It includes some breaking changes that you may need to accommodate for.</p>
<div class="theme-admonition theme-admonition-tip admonition_pzuZ alert alert--success"><div class="admonitionHeading_uJho"><span class="admonitionIcon_vMH2"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>tip</div><div class="admonitionContent_gazR"><p>If you're having trouble working with the changes, please let us know on <a href="https://discord.gg/FSxKq8Tdyg" target="_blank" rel="noopener noreferrer">the typescript-eslint Discord</a>'s <code>#v8</code> channel!</p></div></div>
<h3 class="anchor anchorWithStickyNavbar_eAos" id="ast-breaking-changes">AST Breaking Changes<a href="https://typescript-eslint.io/blog/announcing-typescript-eslint-v8#ast-breaking-changes" class="hash-link" aria-label="Direct link to AST Breaking Changes" title="Direct link to AST Breaking Changes">​</a></h3>
<p>These changes are to 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.</p>
<ul>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/issues/6225" target="_blank" rel="noopener noreferrer">Enhancement: add strict parent types for nodes that have well-defined parents</a>
<ul>
<li>This will help you remove some unnecessary conditions - we suggest using <code>@typescript-eslint/no-unnecessary-condition</code> to help find the unnecessary checks!</li>
</ul>
</li>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/pull/7065" target="_blank" rel="noopener noreferrer">feat(typescript-estree): split TSMappedType typeParameter into constraint and key</a>
<ul>
<li>If your code handles mapped types, change from <code>node.typeParameter.constraint</code> to <code>node.constraint</code> and from <code>node.typeParameter.name</code> to <code>node.key</code></li>
</ul>
</li>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/pull/8933" target="_blank" rel="noopener noreferrer">feat(ast-spec): remove deprecated type params</a>
<ul>
<li>If you haven't already you must stop using those removed AST properties that were already marked as <code>@deprecated</code></li>
</ul>
</li>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/pull/8920" target="_blank" rel="noopener noreferrer">fix(typescript-estree): add TSEnumBody node for TSEnumDeclaration body #8920</a>
<ul>
<li>If your code handles enums, switch from <code>node.members</code> to <code>node.body.members</code></li>
</ul>
</li>
</ul>
<h3 class="anchor anchorWithStickyNavbar_eAos" id="custom-rule-metadocs-types">Custom Rule <code>meta.docs</code> Types<a href="https://typescript-eslint.io/blog/announcing-typescript-eslint-v8#custom-rule-metadocs-types" class="hash-link" aria-label="Direct link to custom-rule-metadocs-types" title="Direct link to custom-rule-metadocs-types">​</a></h3>
<p><code>@typescript-eslint/utils</code> has long exported a <a href="https://typescript-eslint.io/developers/custom-rules#rulecreator" target="_blank" rel="noopener noreferrer"><code>RuleCreator</code> utility</a> for making custom well-typed custom ESLint rules.
That <code>RuleCreator</code> is used internally by <code>@typescript-eslint/eslint-plugin</code> — and in fact, up through typescript-eslint v7, it hardcoded the same types for rules' <code>meta.docs</code> as <code>@typescript-eslint/eslint-plugin</code>!</p>
<p>In typescript-eslint v8, we've made two changes to <code>RuleCreator</code>:</p>
<ul>
<li>Rule <code>meta.docs</code> by default only allows the properties defined in ESLint's <a href="https://eslint.org/docs/latest/extend/custom-rules#rule-structure" target="_blank" rel="noopener noreferrer">Custom Rules &gt; Rule Structure docs</a>: <code>description</code> and <code>url</code></li>
<li><code>RuleCreator</code> allows an optional type parameter to specify additional allowed properties</li>
</ul>
<p>For example, this rule includes the common <code>meta.docs.recommended</code> property as a <code>boolean</code>:</p>
<div class="language-ts codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockContent_m3Ux"><pre class="prism-code language-ts codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line"><span class="token keyword">interface</span><span class="token plain"> </span><span class="token class-name">MyPluginDocs</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  recommended</span><span class="token operator">:</span><span class="token plain"> </span><span class="token builtin">boolean</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token punctuation">}</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token keyword">const</span><span class="token plain"> createRule </span><span class="token operator">=</span><span class="token plain"> ESLintUtils</span><span class="token punctuation">.</span><span class="token generic-function function">RuleCreator</span><span class="token generic-function generic class-name operator">&lt;</span><span class="token generic-function generic class-name">MyPluginDocs</span><span class="token generic-function generic class-name operator">&gt;</span><span class="token punctuation">(</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  name </span><span class="token operator">=&gt;</span><span class="token plain"> </span><span class="token template-string template-punctuation string">`</span><span class="token template-string string">https://example.com/rule/</span><span class="token template-string interpolation interpolation-punctuation punctuation">${</span><span class="token template-string interpolation">name</span><span class="token template-string interpolation interpolation-punctuation punctuation">}</span><span class="token template-string template-punctuation string">`</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token function">createRule</span><span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token comment">// ...</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  meta</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">    docs</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">      description</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'...'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">      recommended</span><span class="token operator">:</span><span class="token plain"> </span><span class="token boolean">true</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">    </span><span class="token punctuation">}</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">    </span><span class="token comment">// ...</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token punctuation">}</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>See <a href="https://github.com/typescript-eslint/typescript-eslint/pull/9025" target="_blank" rel="noopener noreferrer">feat(utils): allow specifying additional rule meta.docs in RuleCreator</a> for more details.</p>
<h3 class="anchor anchorWithStickyNavbar_eAos" id="flat-configuration-ruletester">Flat Configuration <code>RuleTester</code><a href="https://typescript-eslint.io/blog/announcing-typescript-eslint-v8#flat-configuration-ruletester" class="hash-link" aria-label="Direct link to flat-configuration-ruletester" title="Direct link to flat-configuration-ruletester">​</a></h3>
<p>The <code>RuleTester</code> provided by <a href="https://typescript-eslint.io/packages/rule-tester"><code>@typescript-eslint/rule-tester</code></a> is a fork of ESLint's <code>RuleTester</code>.
In typescript-eslint v7 and earlier, <code>RuleTester</code>'s constructor allowed providing legacy "eslintrc" options -- mirroring ESLint v8 and earlier.
In typescript-eslint v8, <code>RuleTester</code>'s constructor now instead allows providing new "flat" config options -- mirroring ESLint v9.</p>
<p>Per ESLint flat configs, any parser configurations you provide will need to be inside a <code>languageOptions</code> property:</p>
<div class="language-ts codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockTitle_P25_">rule.test.ts</div><div class="codeBlockContent_m3Ux"><pre class="prism-code language-ts codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line"><span class="token keyword">import</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"> RuleTester </span><span class="token punctuation">}</span><span class="token plain"> </span><span class="token keyword">from</span><span class="token plain"> '</span><span class="token decorator at operator">@</span><span class="token decorator function">typescript</span><span class="token operator">-</span><span class="token plain">eslint</span><span class="token operator">/</span><span class="token plain">rule</span><span class="token operator">-</span><span class="token plain">tester</span><br></span><span class="token-line"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token keyword">const</span><span class="token plain"> ruleTester </span><span class="token operator">=</span><span class="token plain"> </span><span class="token keyword">new</span><span class="token plain"> </span><span class="token class-name">RuleTester</span><span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line code-block-added-line"><span class="token plain">  languageOptions</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">    parserOptions</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">      tsconfigRootDir</span><span class="token operator">:</span><span class="token plain"> </span><span class="token keyword">import</span><span class="token punctuation">.</span><span class="token plain">meta</span><span class="token punctuation">.</span><span class="token plain">dirname</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">    </span><span class="token punctuation">}</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line code-block-added-line"><span class="token plain">  </span><span class="token punctuation">}</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Any <code>parser</code> you provide will need to be the parser itself, rather than a string name of the package:</p>
<div class="language-ts codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockTitle_P25_">rule.test.ts</div><div class="codeBlockContent_m3Ux"><pre class="prism-code language-ts codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line"><span class="token keyword">import</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"> RuleTester </span><span class="token punctuation">}</span><span class="token plain"> </span><span class="token keyword">from</span><span class="token plain"> '</span><span class="token decorator at operator">@</span><span class="token decorator function">typescript</span><span class="token operator">-</span><span class="token plain">eslint</span><span class="token operator">/</span><span class="token plain">rule</span><span class="token operator">-</span><span class="token plain">tester</span><br></span><span class="token-line code-block-added-line"><span class="token plain"></span><span class="token keyword">import</span><span class="token plain"> jsoncParser </span><span class="token keyword">from</span><span class="token plain"> </span><span class="token string">"jsonc-eslint-parser"</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token keyword">const</span><span class="token plain"> ruleTester </span><span class="token operator">=</span><span class="token plain"> </span><span class="token keyword">new</span><span class="token plain"> </span><span class="token class-name">RuleTester</span><span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line code-block-added-line"><span class="token plain">  languageOptions</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line code-block-added-line"><span class="token plain">    parser</span><span class="token operator">:</span><span class="token plain"> jsoncParser</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line code-block-removed-line"><span class="token plain">    parser</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">"jsonc-eslint-parser"</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line code-block-added-line"><span class="token plain">  </span><span class="token punctuation">}</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>This change brings typescript-eslint's <code>RuleTester</code> in line with ESLint's <code>RuleTester</code> and flat config.
In doing so, it changes two <code>parserOptions</code> defaults:</p>
<ul>
<li><code>ecmaVersion</code>: from <code>5</code> to <code>'latest'</code></li>
<li><code>sourceType</code>: from <code>'script'</code> to <code>'module'</code></li>
</ul>
<p>If you were specifying either or both of those in your tests, you likely can now omit them:</p>
<div class="language-ts codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockTitle_P25_">rule.test.ts</div><div class="codeBlockContent_m3Ux"><pre class="prism-code language-ts codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line"><span class="token keyword">import</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"> RuleTester </span><span class="token punctuation">}</span><span class="token plain"> </span><span class="token keyword">from</span><span class="token plain"> '</span><span class="token decorator at operator">@</span><span class="token decorator function">typescript</span><span class="token operator">-</span><span class="token plain">eslint</span><span class="token operator">/</span><span class="token plain">rule</span><span class="token operator">-</span><span class="token plain">tester</span><br></span><span class="token-line"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line code-block-added-line"><span class="token plain"></span><span class="token keyword">const</span><span class="token plain"> ruleTester </span><span class="token operator">=</span><span class="token plain"> </span><span class="token keyword">new</span><span class="token plain"> </span><span class="token class-name">RuleTester</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line code-block-removed-line"><span class="token plain"></span><span class="token keyword">const</span><span class="token plain"> ruleTester </span><span class="token operator">=</span><span class="token plain"> </span><span class="token keyword">new</span><span class="token plain"> </span><span class="token class-name">RuleTester</span><span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line code-block-removed-line"><span class="token plain">  parserOptions</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line code-block-removed-line"><span class="token plain">    ecmaVersion</span><span class="token operator">:</span><span class="token plain"> </span><span class="token number">2018</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line code-block-removed-line"><span class="token plain">    sourceType</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'module'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line code-block-removed-line"><span class="token plain">  </span><span class="token punctuation">}</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line code-block-removed-line"><span class="token plain"></span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>For more details, see:</p>
<ul>
<li><a href="https://eslint.org/docs/latest/use/migrate-to-9.0.0#-flatruletester-is-now-ruletester" target="_blank" rel="noopener noreferrer">ESLint &gt; Migrate to 9.0.0 &gt; <code>FlatRuleTester</code> is now <code>RuleTester</code></a></li>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/pull/9603" target="_blank" rel="noopener noreferrer">typescript-eslint &gt; feat(rule-tester): switched to flat config</a></li>
</ul>
<h3 class="anchor anchorWithStickyNavbar_eAos" id="support-for-multi-pass-fixes-in-ruletester">Support for multi-pass fixes in <code>RuleTester</code><a href="https://typescript-eslint.io/blog/announcing-typescript-eslint-v8#support-for-multi-pass-fixes-in-ruletester" class="hash-link" aria-label="Direct link to support-for-multi-pass-fixes-in-ruletester" title="Direct link to support-for-multi-pass-fixes-in-ruletester">​</a></h3>
<p>One limitation of ESLint's <code>RuleTester</code> is that it is not possible to verify the individual applied fixes when a rule provides multiple rounds of fixes.
<a href="https://eslint.org/docs/latest/integrate/nodejs-api#testing-fixes" target="_blank" rel="noopener noreferrer">ESLint's <code>RuleTester</code> applies only the first fix</a> when there is conflict between two fixes.</p>
<p>In typescript-eslint v8, our <code>RuleTester</code> tries to apply all possible fixes for each test case.</p>
<p>If your rule tests had some test cases that required multi-pass fixes, you will see some test failures.
To fix these failures, provide an array of strings for <code>output</code> which specifies the output after each fix pass.</p>
<div class="language-ts codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockContent_m3Ux"><pre class="prism-code language-ts codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line"><span class="token keyword">import</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"> RuleTester </span><span class="token punctuation">}</span><span class="token plain"> </span><span class="token keyword">from</span><span class="token plain"> </span><span class="token string">'@typescript-eslint/rule-tester'</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token keyword">import</span><span class="token plain"> rule </span><span class="token keyword">from</span><span class="token plain"> </span><span class="token string">'../src/rules/my-rule.ts'</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token keyword">const</span><span class="token plain"> ruleTester </span><span class="token operator">=</span><span class="token plain"> </span><span class="token keyword">new</span><span class="token plain"> </span><span class="token class-name">RuleTester</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line"><span class="token plain">ruleTester</span><span class="token punctuation">.</span><span class="token function">run</span><span class="token punctuation">(</span><span class="token string">'my-rule'</span><span class="token punctuation">,</span><span class="token plain"> rule</span><span class="token punctuation">,</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  valid</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation">[</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">    </span><span class="token comment">/* ... */</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token punctuation">]</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  invalid</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation">[</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">    </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">      code</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'const a = 1;'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">      </span><span class="token comment">// Remove the line with string form of `output`</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">      output</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'const b = 1;'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">      </span><span class="token comment">// Add the line with array form of `output`</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">      output</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation">[</span><span class="token string">'const b = 1;'</span><span class="token punctuation">,</span><span class="token plain"> </span><span class="token string">'const c = 1;'</span><span class="token punctuation">]</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">      errors</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation">[</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">        </span><span class="token comment">/* ... */</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">      </span><span class="token punctuation">]</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">    </span><span class="token punctuation">}</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token punctuation">]</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>See <a href="https://github.com/typescript-eslint/typescript-eslint/issues/8554" target="_blank" rel="noopener noreferrer">[rule-tester] support multipass fixes</a> for more details.</p>
<h3 class="anchor anchorWithStickyNavbar_eAos" id="other-developer-facing-breaking-changes">Other Developer-Facing Breaking Changes<a href="https://typescript-eslint.io/blog/announcing-typescript-eslint-v8#other-developer-facing-breaking-changes" class="hash-link" aria-label="Direct link to Other Developer-Facing Breaking Changes" title="Direct link to Other Developer-Facing Breaking Changes">​</a></h3>
<ul>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/pull/8617" target="_blank" rel="noopener noreferrer">feat(parser): always enable comment, loc, range, tokens</a>
<ul>
<li>If you were manually calling <code>@typescript-eslint/parser</code> functions, those options are no longer necessary to provide</li>
</ul>
</li>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/pull/8934" target="_blank" rel="noopener noreferrer">chore(type-utils)!: remove IsNullableTypeOptions interface</a>
<ul>
<li>If you were using <code>isNullableType</code>, you can omit its section parameter</li>
</ul>
</li>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/pull/8972" target="_blank" rel="noopener noreferrer">feat(utils): swap LegacyESLint out for FlatESLint as ESLint export</a>
<ul>
<li>If you still need to use the class corresponding to legacy ("eslintrc") configs, switch from importing <code>ESLint</code> to <code>LegacyESLint</code></li>
</ul>
</li>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/pull/8938" target="_blank" rel="noopener noreferrer">chore(type-utils): remove getTypeArguments</a>
<ul>
<li>If you were using <code>getTypeArguments</code>, call a TypeScript type checker's <code>checker.getTypeArguments</code> instead</li>
</ul>
</li>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/pull/9000" target="_blank" rel="noopener noreferrer">feat(utils): remove deprecated context helpers</a>
<ul>
<li>You should consider dropping support for older ESLint versions and migrate to the new APIs.</li>
</ul>
</li>
</ul>
<h2 class="anchor anchorWithStickyNavbar_eAos" id="appreciation">Appreciation<a href="https://typescript-eslint.io/blog/announcing-typescript-eslint-v8#appreciation" class="hash-link" aria-label="Direct link to Appreciation" title="Direct link to Appreciation">​</a></h2>
<p>We'd like to extend a sincere <em>thank you</em> to everybody who pitched in to make typescript-eslint v8 possible.</p>
<ul>
<li>Ourselves on the maintenance team:<!-- -->
<ul>
<li><a href="https://github.com/auvred" target="_blank" rel="noopener noreferrer">Auvred</a></li>
<li><a href="https://github.com/armano2" target="_blank" rel="noopener noreferrer">Armano</a></li>
<li><a href="https://github.com/bradzacher" target="_blank" rel="noopener noreferrer">Brad Zacher</a></li>
<li><a href="https://github.com/JamesHenry" target="_blank" rel="noopener noreferrer">James Henry</a></li>
<li><a href="https://github.com/JoshuaKGoldberg" target="_blank" rel="noopener noreferrer">Josh Goldberg</a></li>
<li><a href="https://github.com/Josh-Cena" target="_blank" rel="noopener noreferrer">Joshua Chen</a></li>
<li><a href="https://github.com/kirkwaiblinger" target="_blank" rel="noopener noreferrer">Kirk Waiblinger</a></li>
</ul>
</li>
<li>Community contributors whose PRs were merged into the 8.0.0 release:<!-- -->
<ul>
<li><a href="https://github.com/abrahamguo" target="_blank" rel="noopener noreferrer">Abraham Guo</a></li>
<li><a href="https://github.com/arka1002" target="_blank" rel="noopener noreferrer">Arka Pratim Chaudhuri</a></li>
<li><a href="https://github.com/higherorderfunctor" target="_blank" rel="noopener noreferrer">Christopher Aubut</a></li>
<li><a href="https://github.com/bachmacintosh" target="_blank" rel="noopener noreferrer">Collin Bachman</a></li>
<li><a href="https://github.com/thuchede" target="_blank" rel="noopener noreferrer">Thomas Huchedé</a></li>
<li><a href="https://github.com/yepitschunked" target="_blank" rel="noopener noreferrer">Victor Lin</a></li>
<li><a href="https://github.com/y-hsgw" target="_blank" rel="noopener noreferrer">Yukihiro Hasegawa</a></li>
</ul>
</li>
<li>Community maintainers and projects who worked with us to try out the v8 beta:<!-- -->
<ul>
<li><a href="https://github.com/babel/babel/pull/16557" target="_blank" rel="noopener noreferrer">Babel</a> with <a href="https://github.com/nicolo-ribaudo" target="_blank" rel="noopener noreferrer">Nicolò Ribaudo</a></li>
<li><a href="https://github.com/t3-oss/create-t3-app/pull/1936" target="_blank" rel="noopener noreferrer">create-t3-app</a> with <a href="https://github.com/juliusmarminge" target="_blank" rel="noopener noreferrer">Julius Marminge</a></li>
<li><a href="https://github.com/csstools/postcss-plugins/pull/1412" target="_blank" rel="noopener noreferrer">postcss-plugins</a> with <a href="https://github.com/romainmenke" target="_blank" rel="noopener noreferrer">Romain Menke</a></li>
<li><a href="https://github.com/prettier/prettier/pull/16333" target="_blank" rel="noopener noreferrer">Prettier</a> with <a href="https://github.com/fisker" target="_blank" rel="noopener noreferrer">fisker Cheung</a></li>
<li><a href="https://github.com/redwoodjs/redwood/pull/10911" target="_blank" rel="noopener noreferrer">RedwoodJS</a> with <a href="https://github.com/Tobbe" target="_blank" rel="noopener noreferrer">Tobbe Lundberg</a></li>
<li><a href="https://github.com/sveltejs/kit/pull/12268" target="_blank" rel="noopener noreferrer">SvelteKit</a> with <a href="https://github.com/benmccann" target="_blank" rel="noopener noreferrer">Ben McCann</a></li>
<li><a href="https://github.com/trpc/trpc/pull/5868" target="_blank" rel="noopener noreferrer">tRPC</a> with <a href="https://github.com/KATT" target="_blank" rel="noopener noreferrer">Alex Katt</a></li>
<li><a href="https://github.com/vitejs/vite/pull/17624" target="_blank" rel="noopener noreferrer">Vite</a> with <a href="https://github.com/bluwy" target="_blank" rel="noopener noreferrer">Bjorn Lu</a></li>
</ul>
</li>
<li>Community plugins and projects who worked with us to try out the v8 beta:<!-- -->
<ul>
<li><a href="https://github.com/eslint-functional/eslint-plugin-functional/pull/809" target="_blank" rel="noopener noreferrer">eslint-plugin-functional</a> with <a href="https://github.com/RebeccaStevens" target="_blank" rel="noopener noreferrer">Rebecca Stevens</a></li>
<li><a href="https://github.com/un-ts/eslint-plugin-import-x/pull/112" target="_blank" rel="noopener noreferrer">eslint-plugin-import-x</a> with <a href="https://github.com/SukkaW" target="_blank" rel="noopener noreferrer">Sukka</a></li>
<li><a href="https://github.com/jest-community/eslint-plugin-jest/pull/1623" target="_blank" rel="noopener noreferrer">eslint-plugin-jest</a> with <a href="https://github.com/SimenB" target="_blank" rel="noopener noreferrer">Simen Bekkhus</a></li>
<li><a href="https://github.com/veritem/eslint-plugin-vitest/pull/479" target="_blank" rel="noopener noreferrer">eslint-plugin-vitest</a> with <a href="https://github.com/veritem" target="_blank" rel="noopener noreferrer">Verité Mugabo</a></li>
<li><a href="https://github.com/Rel1cx/eslint-react/pull/561" target="_blank" rel="noopener noreferrer">eslint-react</a> with <a href="https://github.com/Rel1cx" target="_blank" rel="noopener noreferrer">Eva1ent</a></li>
<li><a href="https://github.com/angular-eslint/angular-eslint/pull/1845" target="_blank" rel="noopener noreferrer">eslint-angular</a> with <a href="https://github.com/JamesHenry" target="_blank" rel="noopener noreferrer">James Henry</a></li>
<li><a href="https://github.com/eslint-stylistic/eslint-stylistic/pull/452" target="_blank" rel="noopener noreferrer">eslint-stylistic</a> with <a href="https://github.com/antfu" target="_blank" rel="noopener noreferrer">Anthony Fu</a></li>
</ul>
</li>
<li>Members of the TypeScript team who helped with performance issues:<!-- -->
<ul>
<li><a href="https://github.com/DanielRosenwasser" target="_blank" rel="noopener noreferrer">Daniel Rosenwasser</a></li>
<li><a href="https://github.com/jakebailey" target="_blank" rel="noopener noreferrer">Jake Bailey</a></li>
<li><a href="https://github.com/sheetalkamat" target="_blank" rel="noopener noreferrer">Sheetal Nandi</a></li>
</ul>
</li>
</ul>
<p>See the <a href="https://github.com/typescript-eslint/typescript-eslint/milestone/9" target="_blank" rel="noopener noreferrer">v8.0.0 milestone</a> for the list of issues and associated merged pull requests.</p>
<h2 class="anchor anchorWithStickyNavbar_eAos" id="supporting-typescript-eslint">Supporting typescript-eslint<a href="https://typescript-eslint.io/blog/announcing-typescript-eslint-v8#supporting-typescript-eslint" class="hash-link" aria-label="Direct link to Supporting typescript-eslint" title="Direct link to Supporting typescript-eslint">​</a></h2>
<p>If you enjoyed this blog post and/or use typescript-eslint, please consider <a href="https://opencollective.com/typescript-eslint" target="_blank" rel="noopener noreferrer">supporting us on Open Collective</a>. We're a small volunteer team and could use your support to make the ESLint experience on TypeScript great. Thanks! 💖</p>]]></content:encoded>
            <category>breaking changes</category>
            <category>typescript-eslint</category>
            <category>v7</category>
            <category>v8</category>
        </item>
        <item>
            <title><![CDATA[Announcing typescript-eslint v8 Beta]]></title>
            <link>https://typescript-eslint.io/blog/announcing-typescript-eslint-v8-beta</link>
            <guid>https://typescript-eslint.io/blog/announcing-typescript-eslint-v8-beta</guid>
            <pubDate>Mon, 27 May 2024 00:00:00 GMT</pubDate>
            <description><![CDATA[Announcing the release of typescript-eslint's v8 beta, including its changes and timeline.]]></description>
            <content:encoded><![CDATA[<div class="theme-admonition theme-admonition-caution admonition_pzuZ alert alert--warning"><div class="admonitionHeading_uJho"><span class="admonitionIcon_vMH2"><svg viewBox="0 0 16 16"><path fill-rule="evenodd" d="M8.893 1.5c-.183-.31-.52-.5-.887-.5s-.703.19-.886.5L.138 13.499a.98.98 0 0 0 0 1.001c.193.31.53.501.886.501h13.964c.367 0 .704-.19.877-.5a1.03 1.03 0 0 0 .01-1.002L8.893 1.5zm.133 11.497H6.987v-2.003h2.039v2.003zm0-3.004H6.987V5.987h2.039v4.006z"></path></svg></span>Newer Information Available</div><div class="admonitionContent_gazR"><p>This blog post is now out of date, as we've released typescript-eslint v8! 🚀
Please see <a href="https://typescript-eslint.io/blog/announcing-typescript-eslint-v8">Announcing typescript-eslint v8</a> for the latest information.</p></div></div>
<!-- -->
<p><a href="https://typescript-eslint.io/" target="_blank" rel="noopener noreferrer">typescript-eslint</a> is the tooling that enables standard JavaScript tools such as <a href="https://eslint.org/" target="_blank" rel="noopener noreferrer">ESLint</a> and <a href="https://prettier.io/" target="_blank" rel="noopener noreferrer">Prettier</a> 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, we're excited to say that typescript-eslint v8 is ready for public beta testing! 🎉</p>
<p>Our plan for typescript-eslint v8 is to:</p>
<ol>
<li>Have users try out betas starting in May of 2024</li>
<li>Respond to user feedback for the next ~1-2 months</li>
<li>Release a stable version within the next ~1-2 months</li>
</ol>
<p>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 <a href="https://discord.gg/FSxKq8Tdyg" target="_blank" rel="noopener noreferrer">the typescript-eslint Discord</a>'s <code>#v8</code> channel!</p>
<h2 class="anchor anchorWithStickyNavbar_eAos" id="trying-out-v8">Trying Out v8<a href="https://typescript-eslint.io/blog/announcing-typescript-eslint-v8-beta#trying-out-v8" class="hash-link" aria-label="Direct link to Trying Out v8" title="Direct link to Trying Out v8">​</a></h2>
<p>Please do try out the typescript-eslint v8 beta!</p>
<h3 class="anchor anchorWithStickyNavbar_eAos" id="as-a-new-user">As A New User<a href="https://typescript-eslint.io/blog/announcing-typescript-eslint-v8-beta#as-a-new-user" class="hash-link" aria-label="Direct link to As A New User" title="Direct link to As A New User">​</a></h3>
<p>If you don't yet use typescript-eslint, you can go through our <a href="https://typescript-eslint.io/getting-started">configuration steps on the v8 <em>Getting Started</em> docs</a>.
It'll walk you through setting up typescript-eslint in a project.</p>
<p>To use v8 specifically, see the following section for an updated install command.</p>
<h3 class="anchor anchorWithStickyNavbar_eAos" id="as-an-existing-user">As An Existing User<a href="https://typescript-eslint.io/blog/announcing-typescript-eslint-v8-beta#as-an-existing-user" class="hash-link" aria-label="Direct link to As An Existing User" title="Direct link to As An Existing User">​</a></h3>
<p>If you already use typescript-eslint, you'll need to first replace your package's previous versions of <code>@typescript-eslint/eslint-plugin</code> and <code>@typescript-eslint/parser</code> with <code>@rc-v8</code> versions:</p>
<div class="tabs-container tabList_hoTN"><ul role="tablist" aria-orientation="horizontal" class="tabs"><li role="tab" tabindex="0" aria-selected="true" class="tabs__item tabItem_dW3K tabs__item--active">Flat Config</li><li role="tab" tabindex="-1" aria-selected="false" class="tabs__item tabItem_dW3K">Legacy Config</li></ul><div class="margin-top--md"><div role="tabpanel" class="tabItem_PzSZ"><div class="language-shell codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockContent_m3Ux"><pre class="prism-code language-shell codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line"><span class="token function">npm</span><span class="token plain"> i typescript-eslint@rc-v8 --save-dev</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div></div><div role="tabpanel" class="tabItem_PzSZ" hidden=""><div class="language-shell codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockContent_m3Ux"><pre class="prism-code language-shell codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line"><span class="token function">npm</span><span class="token plain"> i @typescript-eslint/eslint-plugin@rc-v8 @typescript-eslint/parser@rc-v8 --save-dev</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div></div></div></div>
<p>We highly recommend then basing your ESLint configuration on the reworked typescript-eslint <a href="https://typescript-eslint.io/users/configs">recommended configurations</a> — especially if it's been a while since you've reworked your linter config.</p>
<h2 class="anchor anchorWithStickyNavbar_eAos" id="user-facing-changes">User-Facing Changes<a href="https://typescript-eslint.io/blog/announcing-typescript-eslint-v8-beta#user-facing-changes" class="hash-link" aria-label="Direct link to User-Facing Changes" title="Direct link to User-Facing Changes">​</a></h2>
<p>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 v7 to v8.</p>
<h3 class="anchor anchorWithStickyNavbar_eAos" id="eslint-v9-support">ESLint v9 Support<a href="https://typescript-eslint.io/blog/announcing-typescript-eslint-v8-beta#eslint-v9-support" class="hash-link" aria-label="Direct link to ESLint v9 Support" title="Direct link to ESLint v9 Support">​</a></h3>
<p>typescript-eslint v8 ships with full support for ESLint v9.</p>
<p>typescript-eslint v7 was our first version that supported ESLint's <a href="https://eslint.org/docs/latest/use/configure/configuration-files" target="_blank" rel="noopener noreferrer">new "flat" config file format</a>, which was already available in ESLint v8.
ESLint v9 still supports ESLint's <a href="https://eslint.org/docs/latest/use/configure/configuration-files-deprecated" target="_blank" rel="noopener noreferrer">older legacy config file format</a> so our tooling does as well.
However, ESLint v9 also includes a set of breaking changes that we added support for in typescript-eslint v8.
See the <a href="https://eslint.org/blog/2024/04/eslint-v9.0.0-released" target="_blank" rel="noopener noreferrer">ESLint v9 release blog post</a> for more details.</p>
<h3 class="anchor anchorWithStickyNavbar_eAos" id="project-service">Project Service<a href="https://typescript-eslint.io/blog/announcing-typescript-eslint-v8-beta#project-service" class="hash-link" aria-label="Direct link to Project Service" title="Direct link to Project Service">​</a></h3>
<p>The biggest new feature added in this version is the stability of our new "project service".
In short, the project service is a new way to enable <a href="https://typescript-eslint.io/getting-started/typed-linting">typed linting</a> that is generally <em>easier to configure</em> and <em>faster at runtime</em> than our previous offerings.
It's been experimentally available since v6.1.0 under the name <code>EXPERIMENTAL_useProjectService</code>; now, we've renamed it to <code>projectService</code>.</p>
<p>You can use the new project service in your configuration instead of the previous <code>parserOptions.project</code>:</p>
<div class="language-js codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockTitle_P25_">eslint.config.mjs</div><div class="codeBlockContent_m3Ux"><pre class="prism-code language-js codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line"><span class="token keyword module">import</span><span class="token plain"> </span><span class="token imports">eslint</span><span class="token plain"> </span><span class="token keyword module">from</span><span class="token plain"> </span><span class="token string">'@eslint/js'</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token keyword module">import</span><span class="token plain"> </span><span class="token imports">tseslint</span><span class="token plain"> </span><span class="token keyword module">from</span><span class="token plain"> </span><span class="token string">'typescript-eslint'</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token keyword module">export</span><span class="token plain"> </span><span class="token keyword module">default</span><span class="token plain"> tseslint</span><span class="token punctuation">.</span><span class="token method function property-access">config</span><span class="token punctuation">(</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  eslint</span><span class="token punctuation">.</span><span class="token property-access">configs</span><span class="token punctuation">.</span><span class="token property-access">recommended</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token spread operator">...</span><span class="token plain">tseslint</span><span class="token punctuation">.</span><span class="token property-access">configs</span><span class="token punctuation">.</span><span class="token property-access">recommendedTypeChecked</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">    </span><span class="token literal-property property">languageOptions</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">      </span><span class="token literal-property property">parserOptions</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line code-block-removed-line"><span class="token plain">        </span><span class="token literal-property property">project</span><span class="token operator">:</span><span class="token plain"> </span><span class="token boolean">true</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line code-block-added-line"><span class="token plain">        </span><span class="token literal-property property">projectService</span><span class="token operator">:</span><span class="token plain"> </span><span class="token boolean">true</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">        </span><span class="token literal-property property">tsconfigRootDir</span><span class="token operator">:</span><span class="token plain"> </span><span class="token keyword module">import</span><span class="token punctuation">.</span><span class="token property-access">meta</span><span class="token punctuation">.</span><span class="token property-access">dirname</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">      </span><span class="token punctuation">}</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">    </span><span class="token punctuation">}</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token punctuation">}</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token punctuation">)</span><span class="token punctuation">;</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>The project service will automatically find the closest <code>tsconfig.json</code> for each file (like <code>project: true</code>).
It also allows enabling typed linting for files not explicitly included in a <code>tsconfig.json</code>.
This should remove the need for custom <code>tsconfig.eslint.json</code> files to lint files like <code>eslint.config.mjs</code>!</p>
<p>Typed linting for out-of-project files can be done by specifying two properties of a <code>parserOptions.projectService</code> object:</p>
<ul>
<li><code>allowDefaultProject</code>: a glob of a small number of out-of-project files to enable a slower default project on</li>
<li><code>defaultProject</code>: path to a TypeScript configuration file to use for the slower default project</li>
</ul>
<div class="language-js codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockTitle_P25_">eslint.config.mjs</div><div class="codeBlockContent_m3Ux"><pre class="prism-code language-js codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line"><span class="token keyword module">import</span><span class="token plain"> </span><span class="token imports">eslint</span><span class="token plain"> </span><span class="token keyword module">from</span><span class="token plain"> </span><span class="token string">'@eslint/js'</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token keyword module">import</span><span class="token plain"> </span><span class="token imports">tseslint</span><span class="token plain"> </span><span class="token keyword module">from</span><span class="token plain"> </span><span class="token string">'typescript-eslint'</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token keyword module">export</span><span class="token plain"> </span><span class="token keyword module">default</span><span class="token plain"> tseslint</span><span class="token punctuation">.</span><span class="token method function property-access">config</span><span class="token punctuation">(</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  eslint</span><span class="token punctuation">.</span><span class="token property-access">configs</span><span class="token punctuation">.</span><span class="token property-access">recommended</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token spread operator">...</span><span class="token plain">tseslint</span><span class="token punctuation">.</span><span class="token property-access">configs</span><span class="token punctuation">.</span><span class="token property-access">recommendedTypeChecked</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">    </span><span class="token literal-property property">languageOptions</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">      </span><span class="token literal-property property">parserOptions</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line code-block-removed-line"><span class="token plain">        </span><span class="token literal-property property">project</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation">[</span><span class="token string">'packages/*/tsconfig.json'</span><span class="token punctuation">,</span><span class="token plain"> </span><span class="token string">'tsconfig.eslint.json'</span><span class="token punctuation">]</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line code-block-added-line"><span class="token plain">        </span><span class="token literal-property property">projectService</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line code-block-added-line"><span class="token plain">          </span><span class="token literal-property property">allowDefaultProject</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation">[</span><span class="token string">'*.js'</span><span class="token punctuation">]</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line code-block-added-line"><span class="token plain">          </span><span class="token literal-property property">defaultProject</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'tsconfig.json'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line code-block-added-line"><span class="token plain">        </span><span class="token punctuation">}</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">        </span><span class="token literal-property property">tsconfigRootDir</span><span class="token operator">:</span><span class="token plain"> </span><span class="token keyword module">import</span><span class="token punctuation">.</span><span class="token property-access">meta</span><span class="token punctuation">.</span><span class="token property-access">dirname</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">      </span><span class="token punctuation">}</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">    </span><span class="token punctuation">}</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token punctuation">}</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token punctuation">)</span><span class="token punctuation">;</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Internally, the project service uses the same TypeScript APIs that editors such as VS Code use.
Doing so should make it harder to accidentally configure different type information for ESLint than what you see in day-to-day editing.</p>
<p>We're thrilled to have the project service option promoted to stable in v8.
We'll soon release a <a href="https://github.com/typescript-eslint/typescript-eslint/pull/8031" target="_blank" rel="noopener noreferrer">dedicated <code>parserOptions</code> blog post</a> walking through the new option in more details.
🚀</p>
<h3 class="anchor anchorWithStickyNavbar_eAos" id="updated-configuration-rules">Updated Configuration Rules<a href="https://typescript-eslint.io/blog/announcing-typescript-eslint-v8-beta#updated-configuration-rules" class="hash-link" aria-label="Direct link to Updated Configuration Rules" title="Direct link to Updated Configuration Rules">​</a></h3>
<p>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 <a href="https://github.com/typescript-eslint/typescript-eslint/discussions/8914" target="_blank" rel="noopener noreferrer">Changes to configurations for 8.0.0</a> for a full list of the changes.</p>
<p>Please do try out the new rule configurations presets and let us know in that discussion!</p>
<div class="theme-admonition theme-admonition-tip admonition_pzuZ alert alert--success"><div class="admonitionHeading_uJho"><span class="admonitionIcon_vMH2"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>tip</div><div class="admonitionContent_gazR"><p>If your ESLint configuration contains many <code>rules</code> configurations, we suggest the following strategy to start anew:</p><ol>
<li>Remove all your rules configurations</li>
<li>Extend from the preset configs that make sense for you</li>
<li>Run ESLint on your project</li>
<li>In your ESLint configuration, turn off any rules creating errors that don't make sense for your project — with comments explaining why</li>
<li>In your ESLint configuration and/or with inline <code>eslint-disable</code> comments, turn off / downgrade to "warn" any rules creating too many errors for you to fix — with <em>"TODO"</em> comments linking to tracking issues/tickets to re-enable them</li>
</ol></div></div>
<h3 class="anchor anchorWithStickyNavbar_eAos" id="rule-breaking-changes">Rule Breaking Changes<a href="https://typescript-eslint.io/blog/announcing-typescript-eslint-v8-beta#rule-breaking-changes" class="hash-link" aria-label="Direct link to Rule Breaking Changes" title="Direct link to Rule Breaking Changes">​</a></h3>
<div class="theme-admonition theme-admonition-caution admonition_pzuZ alert alert--warning"><div class="admonitionHeading_uJho"><span class="admonitionIcon_vMH2"><svg viewBox="0 0 16 16"><path fill-rule="evenodd" d="M8.893 1.5c-.183-.31-.52-.5-.887-.5s-.703.19-.886.5L.138 13.499a.98.98 0 0 0 0 1.001c.193.31.53.501.886.501h13.964c.367 0 .704-.19.877-.5a1.03 1.03 0 0 0 .01-1.002L8.893 1.5zm.133 11.497H6.987v-2.003h2.039v2.003zm0-3.004H6.987V5.987h2.039v4.006z"></path></svg></span>Newer Information Available</div><div class="admonitionContent_gazR"><p>This blog post is now out of date, as we've released typescript-eslint v8! 🚀
Please see <a href="https://typescript-eslint.io/blog/announcing-typescript-eslint-v8">Announcing typescript-eslint v8</a> for the latest information.</p></div></div>
<p>Several rules are changed in significant enough ways to be considered breaking changes:</p>
<ul>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/issues/8333" target="_blank" rel="noopener noreferrer">Rules: Deprecate prefer-ts-expect-error in favor of ban-ts-comment</a>
<ul>
<li>If you have <a href="https://typescript-eslint.io/rules/prefer-ts-expect-error"><code>@typescript-eslint/prefer-ts-expect-error</code></a> manually enabled, remove that, and instead either use a <a href="https://typescript-eslint.io/users/configs">recommended config</a> or manually enable <a href="https://typescript-eslint.io/rules/ban-ts-comment"><code>@typescript-eslint/ban-ts-comment</code></a>.</li>
</ul>
</li>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/pull/8334" target="_blank" rel="noopener noreferrer">chore(eslint-plugin): deprecate no-var-requires in favor of no-require-imports</a>
<ul>
<li>If you have <a href="https://typescript-eslint.io/rules/no-var-requires"><code>@typescript-eslint/no-var-requires</code></a> manually enabled, remove that, and instead either use a <a href="https://typescript-eslint.io/users/configs">recommended config</a> or manually enable <a href="https://typescript-eslint.io/rules/no-require-imports"><code>@typescript-eslint/no-require-imports</code></a>.</li>
</ul>
</li>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/issues/9083" target="_blank" rel="noopener noreferrer">feat(eslint-plugin): remove deprecated no-throw-literal rule</a>
<ul>
<li>If you have <a href="https://typescript-eslint.io/rules/no-throw-literal" target="_blank" rel="noopener noreferrer"><code>@typescript-eslint/no-throw-literal</code></a> manually enabled, remove that, and instead either use a <a href="https://typescript-eslint.io/users/configs">recommended config</a> or manually enable <a href="https://typescript-eslint.io/rules/only-throw-error"><code>@typescript-eslint/only-throw-error</code></a>.</li>
</ul>
</li>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/pull/8821" target="_blank" rel="noopener noreferrer">feat(eslint-plugin): [no-useless-template-literals] rename to no-useless-template-expression (deprecate no-useless-template-literals)</a> and <a href="https://github.com/typescript-eslint/typescript-eslint/pull/9174" target="_blank" rel="noopener noreferrer">fix: no-useless-template-expression -&gt; no-unnecessary-template-expression</a>
<ul>
<li>Find-and-replace text from <code>no-useless-template-literals</code> to <code>no-unnecessary-template-expression</code></li>
</ul>
</li>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/pull/8832" target="_blank" rel="noopener noreferrer">feat(eslint-plugin): deprecate no-loss-of-precision extension rule</a>
<ul>
<li>If you have <a href="https://typescript-eslint.io/rules/no-loss-of-precision"><code>@typescript-eslint/no-loss-of-precision</code></a> manually enabled, replace it with the base rule <code>no-loss-of-precision</code>.</li>
</ul>
</li>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/pull/8833" target="_blank" rel="noopener noreferrer">feat(eslint-plugin): remove formatting/layout rules</a>
<ul>
<li>If you're using any of the old deprecated formatting rules, see <a href="https://eslint.style/" target="_blank" rel="noopener noreferrer">eslint.style</a> for their new equivalents</li>
</ul>
</li>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/pull/8872" target="_blank" rel="noopener noreferrer">feat(eslint-plugin): [prefer-nullish-coalescing] change ignoreConditionalTests default to true</a>
<ul>
<li>If you want to have the rule check conditional tests, set its <a href="https://typescript-eslint.io/rules/prefer-nullish-coalescing/#ignoreconditionaltests"><code>ignoreConditionalTests</code> option</a> to <code>false</code> in your ESLint config</li>
</ul>
</li>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/pull/8971" target="_blank" rel="noopener noreferrer">feat(eslint-plugin): [no-unused-vars] align catch behavior to ESLint 9</a>
<ul>
<li>If you want <a href="https://typescript-eslint.io/rules/no-unused-vars"><code>@typescript-eslint/no-unused-vars</code></a> to ignore caught errors, enable its <code>caughtErrors</code> option to <code>'none'</code> in your ESLint config</li>
</ul>
</li>
</ul>
<h4 class="anchor anchorWithStickyNavbar_eAos" id="replacement-of-ban-types">Replacement of <code>ban-types</code><a href="https://typescript-eslint.io/blog/announcing-typescript-eslint-v8-beta#replacement-of-ban-types" class="hash-link" aria-label="Direct link to replacement-of-ban-types" title="Direct link to replacement-of-ban-types">​</a></h4>
<p><a href="https://typescript-eslint.io/rules/ban-types" target="_blank" rel="noopener noreferrer"><code>@typescript-eslint/ban-types</code></a> has long been one of the more controversial rules in typescript-eslint.
It served two purposes:</p>
<ul>
<li>Allowing users to ban a configurable list of types from being used in type annotations</li>
<li>Banning confusing or dangerous built-in types such as <code>Function</code> and <code>Number</code></li>
</ul>
<p>Notably, <code>ban-types</code> banned the built-in <code>{}</code> ("empty object") type in TypeScript.
The <code>{}</code> type is a common source of confusion for TypeScript developers because it matches <em>any non-nullable</em> value, including primitives like <code>""</code>.</p>
<p>Banning <code>{}</code> in <code>ban-types</code> was helpful to prevent developers from accidentally using it instead of a more safe type such as <code>object</code>.
On the other hand, there are legitimate uses for <code>{}</code>, and banning it by default was harmful in those cases.</p>
<p>typescript-eslint v8 deletes the <code>ban-types</code> rule and replaces it with several more targeted rules:</p>
<ul>
<li><a href="https://typescript-eslint.io/rules/no-restricted-types"><code>@typescript-eslint/no-restricted-types</code></a> is the new rule for banning a configurable list of type names.
It has no options enabled by default.
It has no options enabled by default.</li>
<li><a href="https://typescript-eslint.io/rules/no-empty-object-type"><code>@typescript-eslint/no-empty-object-type</code></a> bans the built-in <code>{}</code> type in confusing locations.</li>
<li><a href="https://typescript-eslint.io/rules/no-unsafe-function-type"><code>@typescript-eslint/no-unsafe-function-type</code></a> bans the built-in <code>Function</code> type.</li>
<li><a href="https://typescript-eslint.io/rules/no-wrapper-object-types"><code>@typescript-eslint/no-wrapper-object-types</code></a> bans <code>Object</code> and built-in class wrappers such as <code>Number</code>.</li>
</ul>
<p>To migrate to the new rules:</p>
<ul>
<li>If you were disabling the ban on <code>{}</code>, consider enabling <a href="https://typescript-eslint.io/rules/no-empty-object-type"><code>@typescript-eslint/no-empty-object-type</code></a>, as it allows some cases of <code>{}</code> that were previously banned.</li>
<li>If you were banning any configurable types lists, provide a similar configuration to <a href="https://typescript-eslint.io/rules/no-restricted-types"><code>no-restricted-types</code></a>.</li>
<li>If you have <a href="https://typescript-eslint.io/rules/ban-types"><code>@typescript-eslint/ban-types</code></a> manually enabled, it will no longer ban:<!-- -->
<ul>
<li><code>{}</code> or <code>object</code>: use a <a href="https://typescript-eslint.io/users/configs">recommended config</a> or manually enable <a href="https://typescript-eslint.io/rules/no-empty-object-type"><code>@typescript-eslint/no-empty-object-type</code></a>.</li>
<li><code>Function</code>: use a <a href="https://typescript-eslint.io/users/configs">recommended config</a> or manually enable <a href="https://typescript-eslint.io/rules/no-unsafe-function-type"><code>@typescript-eslint/no-unsafe-function-type</code></a>.</li>
<li><code>Number</code> or other built-in uppercase types: use a <a href="https://typescript-eslint.io/users/configs">recommended config</a> or manually enable <a href="https://typescript-eslint.io/rules/no-wrapper-object-types"><code>@typescript-eslint/no-wrapper-object-types</code></a>.</li>
</ul>
</li>
<li>If you have <a href="https://typescript-eslint.io/rules/no-empty-interface"><code>@typescript-eslint/no-empty-interface</code></a> manually enabled, remove that, and instead either use a <a href="https://typescript-eslint.io/users/configs">recommended config</a> or manually enable <a href="https://typescript-eslint.io/rules/no-empty-object-type"><code>@typescript-eslint/no-empty-object-type</code></a>.</li>
</ul>
<p>For more details, see the issues and pull requests that split apart the <code>ban-types</code> rule:</p>
<ul>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/issues/8700" target="_blank" rel="noopener noreferrer">Enhancement: [ban-types] Split the <!-- --> ban into a separate, better-phrased rule</a></li>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/pull/8977" target="_blank" rel="noopener noreferrer">feat(eslint-plugin): split no-empty-object-type out from ban-types and no-empty-interface</a></li>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/issues/8978" target="_blank" rel="noopener noreferrer">Enhancement: [ban-types] Split into default-less no-restricted-types and more targeted type ban rule(s)</a></li>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/pull/9102" target="_blank" rel="noopener noreferrer">feat(eslint-plugin): replace ban-types with no-restricted-types, no-unsafe-function-type, no-wrapper-object-types</a></li>
</ul>
<h3 class="anchor anchorWithStickyNavbar_eAos" id="tooling-breaking-changes">Tooling Breaking Changes<a href="https://typescript-eslint.io/blog/announcing-typescript-eslint-v8-beta#tooling-breaking-changes" class="hash-link" aria-label="Direct link to Tooling Breaking Changes" title="Direct link to Tooling Breaking Changes">​</a></h3>
<div class="theme-admonition theme-admonition-caution admonition_pzuZ alert alert--warning"><div class="admonitionHeading_uJho"><span class="admonitionIcon_vMH2"><svg viewBox="0 0 16 16"><path fill-rule="evenodd" d="M8.893 1.5c-.183-.31-.52-.5-.887-.5s-.703.19-.886.5L.138 13.499a.98.98 0 0 0 0 1.001c.193.31.53.501.886.501h13.964c.367 0 .704-.19.877-.5a1.03 1.03 0 0 0 .01-1.002L8.893 1.5zm.133 11.497H6.987v-2.003h2.039v2.003zm0-3.004H6.987V5.987h2.039v4.006z"></path></svg></span>Newer Information Available</div><div class="admonitionContent_gazR"><p>This blog post is now out of date, as we've released typescript-eslint v8! 🚀
Please see <a href="https://typescript-eslint.io/blog/announcing-typescript-eslint-v8">Announcing typescript-eslint v8</a> for the latest information.</p></div></div>
<ul>
<li><del><a href="https://github.com/typescript-eslint/typescript-eslint/issues/6403" target="_blank" rel="noopener noreferrer">Enhancement: Error if configuration options aren't provided as expected</a></del>: postponed to a future major version</li>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/pull/8818" target="_blank" rel="noopener noreferrer">fix(typescript-estree): enable dot globs for project by default</a>
<ul>
<li>This will cause any <code>parserOptions.project</code> globs to match dot (<code>.</code>) directories.
If you don't want to match them then use a more specific set of globs, or switch to <code>parserOptions.projectService</code>.</li>
</ul>
</li>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/pull/8834" target="_blank" rel="noopener noreferrer">feat(typescript-estree): remove slow deprecated and isolated programs</a>
<ul>
<li>If you were still using <code>parserOptions.DEPRECATED__createDefaultProgram</code>, switch to <code>parserOptions.projectService</code> <em>(recommended)</em> or <code>parserOptions.project</code>.</li>
</ul>
</li>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/pull/8922" target="_blank" rel="noopener noreferrer">feat(typescript-estree): rename automaticSingleRunInference to disallowAutomaticSingleRunInference</a>
<ul>
<li>We've updated the default to be an opt-out - meaning you no longer need to enable it:<!-- -->
<div class="language-js codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockContent_m3Ux"><pre class="prism-code language-js codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line"><span class="token literal-property property">parserOptions</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line code-block-removed-line"><span class="token plain">  </span><span class="token literal-property property">automaticSingleRunInference</span><span class="token operator">:</span><span class="token plain"> </span><span class="token boolean">true</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token comment">// ...</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token punctuation">}</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
</li>
</ul>
</li>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/pull/8973" target="_blank" rel="noopener noreferrer">chore: bump minimum versions for v8</a>
<ul>
<li>ESLint support range was changed from <code>^8.56.0</code> to <code>^8.57.0</code></li>
<li>Node.js support range was changed from <code>^18.18.0 || &gt;=20.0.0</code> to <code>^18.18.0 || ^20.9.0 || &gt;=21.1.0</code></li>
<li>TypeScript support range was changed from <code>&gt;=4.7.4 &lt;5.5.0</code> to <code>&gt;=4.8.4 &lt;5.5.0</code></li>
</ul>
</li>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/issues/9088" target="_blank" rel="noopener noreferrer">Parser: remove EXPERIMENTAL_useSourceOfProjectReferenceRedirect in favor of project service</a>
<ul>
<li>We now recommend using the new <a href="https://typescript-eslint.io/blog/announcing-typescript-eslint-v8-beta#project-service"><code>parserOptions.projectService</code></a> instead</li>
</ul>
</li>
</ul>
<h2 class="anchor anchorWithStickyNavbar_eAos" id="developer-facing-changes">Developer-Facing Changes<a href="https://typescript-eslint.io/blog/announcing-typescript-eslint-v8-beta#developer-facing-changes" class="hash-link" aria-label="Direct link to Developer-Facing Changes" title="Direct link to Developer-Facing Changes">​</a></h2>
<p>typescript-eslint v8 comes with a suite of cleanups and improvements for developers using its Node.js APIs as well.
If you author any ESLint plugins or other tools that interact with TypeScript syntax, then we recommend you try out typescript-eslint v8 soon.
It includes some breaking changes that you may need to accommodate for.</p>
<div class="theme-admonition theme-admonition-tip admonition_pzuZ alert alert--success"><div class="admonitionHeading_uJho"><span class="admonitionIcon_vMH2"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>tip</div><div class="admonitionContent_gazR"><p>If you're having trouble working with the changes, please let us know on <a href="https://discord.gg/FSxKq8Tdyg" target="_blank" rel="noopener noreferrer">the typescript-eslint Discord</a>'s <code>#v8</code> channel!</p></div></div>
<h3 class="anchor anchorWithStickyNavbar_eAos" id="ast-breaking-changes">AST Breaking Changes<a href="https://typescript-eslint.io/blog/announcing-typescript-eslint-v8-beta#ast-breaking-changes" class="hash-link" aria-label="Direct link to AST Breaking Changes" title="Direct link to AST Breaking Changes">​</a></h3>
<p>These changes are to 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.</p>
<ul>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/issues/6225" target="_blank" rel="noopener noreferrer">Enhancement: add strict parent types for nodes that have well-defined parents</a>
<ul>
<li>This will help you remove some unnecessary conditions - we suggest using <code>@typescript-eslint/no-unnecessary-condition</code> to help find the unnecessary checks!</li>
</ul>
</li>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/pull/7065" target="_blank" rel="noopener noreferrer">feat(typescript-estree): split TSMappedType typeParameter into constraint and key</a>
<ul>
<li>If your code handles mapped types, change from <code>node.typeParameter.constraint</code> to <code>node.constraint</code> and from <code>node.typeParameter.name</code> to <code>node.key</code></li>
</ul>
</li>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/pull/8933" target="_blank" rel="noopener noreferrer">feat(ast-spec): remove deprecated type params</a>
<ul>
<li>If you haven't already you must stop using those removed AST properties that were already marked as <code>@deprecated</code></li>
</ul>
</li>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/pull/8920" target="_blank" rel="noopener noreferrer">fix(typescript-estree): add TSEnumBody node for TSEnumDeclaration body #8920</a>
<ul>
<li>If your code handles enums, switch from <code>node.members</code> to <code>node.body.members</code></li>
</ul>
</li>
</ul>
<h3 class="anchor anchorWithStickyNavbar_eAos" id="custom-rule-metadocs-types">Custom Rule <code>meta.docs</code> Types<a href="https://typescript-eslint.io/blog/announcing-typescript-eslint-v8-beta#custom-rule-metadocs-types" class="hash-link" aria-label="Direct link to custom-rule-metadocs-types" title="Direct link to custom-rule-metadocs-types">​</a></h3>
<p><code>@typescript-eslint/utils</code> has long exported a <a href="https://typescript-eslint.io/developers/custom-rules#rulecreator" target="_blank" rel="noopener noreferrer"><code>RuleCreator</code> utility</a> for making custom well-typed custom ESLint rules.
That <code>RuleCreator</code> is used internally by <code>@typescript-eslint/eslint-plugin</code> — and in fact, up through typescript-eslint v7, it hardcoded the same types for rules' <code>meta.docs</code> as <code>@typescript-eslint/eslint-plugin</code>!</p>
<p>In typescript-eslint v8, we've made two changes to <code>RuleCreator</code>:</p>
<ul>
<li>Rule <code>meta.docs</code> by default only allows the properties defined in ESLint's <a href="https://eslint.org/docs/latest/extend/custom-rules#rule-structure" target="_blank" rel="noopener noreferrer">Custom Rules &gt; Rule Structure docs</a>: <code>description</code> and <code>url</code></li>
<li><code>RuleCreator</code> allows an optional type parameter to specify additional allowed properties</li>
</ul>
<p>For example, this rule includes the common <code>meta.docs.recommended</code> property as a <code>boolean</code>:</p>
<div class="language-ts codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockContent_m3Ux"><pre class="prism-code language-ts codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line"><span class="token keyword">interface</span><span class="token plain"> </span><span class="token class-name">MyPluginDocs</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  recommended</span><span class="token operator">:</span><span class="token plain"> </span><span class="token builtin">boolean</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token punctuation">}</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token keyword">const</span><span class="token plain"> createRule </span><span class="token operator">=</span><span class="token plain"> ESLintUtils</span><span class="token punctuation">.</span><span class="token generic-function function">RuleCreator</span><span class="token generic-function generic class-name operator">&lt;</span><span class="token generic-function generic class-name">MyPluginDocs</span><span class="token generic-function generic class-name operator">&gt;</span><span class="token punctuation">(</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  name </span><span class="token operator">=&gt;</span><span class="token plain"> </span><span class="token template-string template-punctuation string">`</span><span class="token template-string string">https://example.com/rule/</span><span class="token template-string interpolation interpolation-punctuation punctuation">${</span><span class="token template-string interpolation">name</span><span class="token template-string interpolation interpolation-punctuation punctuation">}</span><span class="token template-string template-punctuation string">`</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token function">createRule</span><span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token comment">// ...</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  meta</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">    docs</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">      description</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'...'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">      recommended</span><span class="token operator">:</span><span class="token plain"> </span><span class="token boolean">true</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">    </span><span class="token punctuation">}</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">    </span><span class="token comment">// ...</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token punctuation">}</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>See <a href="https://github.com/typescript-eslint/typescript-eslint/pull/9025" target="_blank" rel="noopener noreferrer">feat(utils): allow specifying additional rule meta.docs in RuleCreator</a> for more details.</p>
<h3 class="anchor anchorWithStickyNavbar_eAos" id="flat-configuration-ruletester">Flat Configuration <code>RuleTester</code><a href="https://typescript-eslint.io/blog/announcing-typescript-eslint-v8-beta#flat-configuration-ruletester" class="hash-link" aria-label="Direct link to flat-configuration-ruletester" title="Direct link to flat-configuration-ruletester">​</a></h3>
<div class="theme-admonition theme-admonition-note admonition_pzuZ alert alert--secondary"><div class="admonitionHeading_uJho"><span class="admonitionIcon_vMH2"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>note</div><div class="admonitionContent_gazR"><p>This breaking change was missed in the initial versions of this blog post.</p></div></div>
<p>The <code>RuleTester</code> provided by <a href="https://typescript-eslint.io/packages/rule-tester"><code>@typescript-eslint/rule-tester</code></a> is a fork of ESLint's <code>RuleTester</code>.
In typescript-eslint v7 and earlier, <code>RuleTester</code>'s constructor allowed providing legacy "eslintrc" options -- mirroring ESLint v8 and earlier.
In typescript-eslint v8, <code>RuleTester</code>'s constructor now instead allows providing new "flat" config options -- mirroring ESLint v9.</p>
<p>Per ESLint flat configs, any parser configurations you provide will need to be inside a <code>languageOptions</code> property:</p>
<div class="language-ts codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockTitle_P25_">rule.test.ts</div><div class="codeBlockContent_m3Ux"><pre class="prism-code language-ts codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line"><span class="token keyword">import</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"> RuleTester </span><span class="token punctuation">}</span><span class="token plain"> </span><span class="token keyword">from</span><span class="token plain"> '</span><span class="token decorator at operator">@</span><span class="token decorator function">typescript</span><span class="token operator">-</span><span class="token plain">eslint</span><span class="token operator">/</span><span class="token plain">rule</span><span class="token operator">-</span><span class="token plain">tester</span><br></span><span class="token-line"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token keyword">const</span><span class="token plain"> ruleTester </span><span class="token operator">=</span><span class="token plain"> </span><span class="token keyword">new</span><span class="token plain"> </span><span class="token class-name">RuleTester</span><span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line code-block-added-line"><span class="token plain">  languageOptions</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">    parserOptions</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">      tsconfigRootDir</span><span class="token operator">:</span><span class="token plain"> </span><span class="token keyword">import</span><span class="token punctuation">.</span><span class="token plain">meta</span><span class="token punctuation">.</span><span class="token plain">dirname</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">    </span><span class="token punctuation">}</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line code-block-added-line"><span class="token plain">  </span><span class="token punctuation">}</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Any <code>parser</code> you provide will need to be the parser itself, rather than a string name of the package:</p>
<div class="language-ts codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockTitle_P25_">rule.test.ts</div><div class="codeBlockContent_m3Ux"><pre class="prism-code language-ts codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line"><span class="token keyword">import</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"> RuleTester </span><span class="token punctuation">}</span><span class="token plain"> </span><span class="token keyword">from</span><span class="token plain"> '</span><span class="token decorator at operator">@</span><span class="token decorator function">typescript</span><span class="token operator">-</span><span class="token plain">eslint</span><span class="token operator">/</span><span class="token plain">rule</span><span class="token operator">-</span><span class="token plain">tester</span><br></span><span class="token-line code-block-added-line"><span class="token plain"></span><span class="token keyword">import</span><span class="token plain"> jsoncParser </span><span class="token keyword">from</span><span class="token plain"> </span><span class="token string">"jsonc-eslint-parser"</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token keyword">const</span><span class="token plain"> ruleTester </span><span class="token operator">=</span><span class="token plain"> </span><span class="token keyword">new</span><span class="token plain"> </span><span class="token class-name">RuleTester</span><span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line code-block-added-line"><span class="token plain">  languageOptions</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line code-block-added-line"><span class="token plain">    parser</span><span class="token operator">:</span><span class="token plain"> jsoncParser</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line code-block-removed-line"><span class="token plain">    parser</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">"jsonc-eslint-parser"</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line code-block-added-line"><span class="token plain">  </span><span class="token punctuation">}</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>This change brings typescript-eslint's <code>RuleTester</code> in line with ESLint's <code>RuleTester</code> and flat config.
In doing so, it changes two <code>parserOptions</code> defaults:</p>
<ul>
<li><code>ecmaVersion</code>: from <code>5</code> to <code>'latest'</code></li>
<li><code>sourceType</code>: from <code>'script'</code> to <code>'module'</code></li>
</ul>
<p>If you were specifying either or both of those in your tests, you likely can now omit them:</p>
<div class="language-ts codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockTitle_P25_">rule.test.ts</div><div class="codeBlockContent_m3Ux"><pre class="prism-code language-ts codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line"><span class="token keyword">import</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"> RuleTester </span><span class="token punctuation">}</span><span class="token plain"> </span><span class="token keyword">from</span><span class="token plain"> '</span><span class="token decorator at operator">@</span><span class="token decorator function">typescript</span><span class="token operator">-</span><span class="token plain">eslint</span><span class="token operator">/</span><span class="token plain">rule</span><span class="token operator">-</span><span class="token plain">tester</span><br></span><span class="token-line"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line code-block-added-line"><span class="token plain"></span><span class="token keyword">const</span><span class="token plain"> ruleTester </span><span class="token operator">=</span><span class="token plain"> </span><span class="token keyword">new</span><span class="token plain"> </span><span class="token class-name">RuleTester</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line code-block-removed-line"><span class="token plain"></span><span class="token keyword">const</span><span class="token plain"> ruleTester </span><span class="token operator">=</span><span class="token plain"> </span><span class="token keyword">new</span><span class="token plain"> </span><span class="token class-name">RuleTester</span><span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line code-block-removed-line"><span class="token plain">  parserOptions</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line code-block-removed-line"><span class="token plain">    ecmaVersion</span><span class="token operator">:</span><span class="token plain"> </span><span class="token number">2018</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line code-block-removed-line"><span class="token plain">    sourceType</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'module'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line code-block-removed-line"><span class="token plain">  </span><span class="token punctuation">}</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line code-block-removed-line"><span class="token plain"></span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>For more details, see:</p>
<ul>
<li><a href="https://eslint.org/docs/latest/use/migrate-to-9.0.0#-flatruletester-is-now-ruletester" target="_blank" rel="noopener noreferrer">ESLint &gt; Migrate to 9.0.0 &gt; <code>FlatRuleTester</code> is now <code>RuleTester</code></a></li>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/pull/9603" target="_blank" rel="noopener noreferrer">typescript-eslint &gt; feat(rule-tester): switched to flat config</a></li>
</ul>
<h3 class="anchor anchorWithStickyNavbar_eAos" id="support-for-multi-pass-fixes-in-ruletester">Support for multi-pass fixes in <code>RuleTester</code><a href="https://typescript-eslint.io/blog/announcing-typescript-eslint-v8-beta#support-for-multi-pass-fixes-in-ruletester" class="hash-link" aria-label="Direct link to support-for-multi-pass-fixes-in-ruletester" title="Direct link to support-for-multi-pass-fixes-in-ruletester">​</a></h3>
<p>One limitation of ESLint's <code>RuleTester</code> is that it is not possible to verify the individual applied fixes when a rule provides multiple rounds of fixes.
<a href="https://eslint.org/docs/latest/integrate/nodejs-api#testing-fixes" target="_blank" rel="noopener noreferrer">ESLint's <code>RuleTester</code> applies only the first fix</a> when there is conflict between two fixes.</p>
<p>In typescript-eslint v8, our <code>RuleTester</code> tries to apply all possible fixes for each test case.</p>
<p>If your rule tests had some test cases that required multi-pass fixes, you will see some test failures.
To fix these failures, provide an array of strings for <code>output</code> which specifies the output after each fix pass.</p>
<div class="language-ts codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockContent_m3Ux"><pre class="prism-code language-ts codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line"><span class="token keyword">import</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"> RuleTester </span><span class="token punctuation">}</span><span class="token plain"> </span><span class="token keyword">from</span><span class="token plain"> </span><span class="token string">'@typescript-eslint/rule-tester'</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token keyword">import</span><span class="token plain"> rule </span><span class="token keyword">from</span><span class="token plain"> </span><span class="token string">'../src/rules/my-rule.ts'</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token keyword">const</span><span class="token plain"> ruleTester </span><span class="token operator">=</span><span class="token plain"> </span><span class="token keyword">new</span><span class="token plain"> </span><span class="token class-name">RuleTester</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line"><span class="token plain">ruleTester</span><span class="token punctuation">.</span><span class="token function">run</span><span class="token punctuation">(</span><span class="token string">'my-rule'</span><span class="token punctuation">,</span><span class="token plain"> rule</span><span class="token punctuation">,</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  valid</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation">[</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">    </span><span class="token comment">/* ... */</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token punctuation">]</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  invalid</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation">[</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">    </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">      code</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'const a = 1;'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">      </span><span class="token comment">// Remove the line with string form of `output`</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">      output</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'const b = 1;'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">      </span><span class="token comment">// Add the line with array form of `output`</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">      output</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation">[</span><span class="token string">'const b = 1;'</span><span class="token punctuation">,</span><span class="token plain"> </span><span class="token string">'const c = 1;'</span><span class="token punctuation">]</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">      errors</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation">[</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">        </span><span class="token comment">/* ... */</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">      </span><span class="token punctuation">]</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">    </span><span class="token punctuation">}</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token punctuation">]</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>See <a href="https://github.com/typescript-eslint/typescript-eslint/issues/8554" target="_blank" rel="noopener noreferrer">[rule-tester] support multipass fixes</a> for more details.</p>
<h3 class="anchor anchorWithStickyNavbar_eAos" id="other-developer-facing-breaking-changes">Other Developer-Facing Breaking Changes<a href="https://typescript-eslint.io/blog/announcing-typescript-eslint-v8-beta#other-developer-facing-breaking-changes" class="hash-link" aria-label="Direct link to Other Developer-Facing Breaking Changes" title="Direct link to Other Developer-Facing Breaking Changes">​</a></h3>
<ul>
<li><del><a href="https://github.com/typescript-eslint/typescript-eslint/issues/5439" target="_blank" rel="noopener noreferrer">Repo: Rule [options] parameter should be non-nullable if defaultOptions exists</a></del>: blocked on external features in ESLint and TypeScript</li>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/pull/8617" target="_blank" rel="noopener noreferrer">feat(parser): always enable comment, loc, range, tokens</a>
<ul>
<li>If you were manually calling <code>@typescript-eslint/parser</code> functions, those options are no longer necessary to provide</li>
</ul>
</li>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/pull/8934" target="_blank" rel="noopener noreferrer">chore(type-utils)!: remove IsNullableTypeOptions interface</a>
<ul>
<li>If you were using <code>isNullableType</code>, you can omit its section parameter</li>
</ul>
</li>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/pull/8972" target="_blank" rel="noopener noreferrer">feat(utils): swap LegacyESLint out for FlatESLint as ESLint export</a>
<ul>
<li>If you still need to use the class corresponding to legacy ("eslintrc") configs, switch from importing <code>ESLint</code> to <code>LegacyESLint</code></li>
</ul>
</li>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/pull/8938" target="_blank" rel="noopener noreferrer">chore(type-utils): remove getTypeArguments</a>
<ul>
<li>If you were using <code>getTypeArguments</code>, call a TypeScript type checker's <code>checker.getTypeArguments</code> instead</li>
</ul>
</li>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/pull/9000" target="_blank" rel="noopener noreferrer">feat(utils): remove deprecated context helpers</a>
<ul>
<li>You should consider dropping support for older ESLint versions and migrate to the new APIs.</li>
</ul>
</li>
</ul>
<h2 class="anchor anchorWithStickyNavbar_eAos" id="appreciation">Appreciation<a href="https://typescript-eslint.io/blog/announcing-typescript-eslint-v8-beta#appreciation" class="hash-link" aria-label="Direct link to Appreciation" title="Direct link to Appreciation">​</a></h2>
<p>We'd like to extend a sincere <em>thank you</em> to everybody who pitched in to make typescript-eslint v8 possible.</p>
<ul>
<li>Ourselves on the maintenance team:<!-- -->
<ul>
<li><a href="https://github.com/auvred" target="_blank" rel="noopener noreferrer">Auvred</a></li>
<li><a href="https://github.com/armano2" target="_blank" rel="noopener noreferrer">Armano</a></li>
<li><a href="https://github.com/bradzacher" target="_blank" rel="noopener noreferrer">Brad Zacher</a></li>
<li><a href="https://github.com/JamesHenry" target="_blank" rel="noopener noreferrer">James Henry</a></li>
<li><a href="https://github.com/JoshuaKGoldberg" target="_blank" rel="noopener noreferrer">Josh Goldberg</a></li>
<li><a href="https://github.com/Josh-Cena" target="_blank" rel="noopener noreferrer">Joshua Chen</a></li>
<li><a href="https://github.com/kirkwaiblinger" target="_blank" rel="noopener noreferrer">Kirk Waiblinger</a></li>
</ul>
</li>
<li>Community contributors whose PRs were merged into the 8.0.0 release:<!-- -->
<ul>
<li><a href="https://github.com/abrahamguo" target="_blank" rel="noopener noreferrer">Abraham Guo</a></li>
<li><a href="https://github.com/arka1002" target="_blank" rel="noopener noreferrer">Arka Pratim Chaudhuri</a></li>
<li><a href="https://github.com/higherorderfunctor" target="_blank" rel="noopener noreferrer">Christopher Aubut</a></li>
<li><a href="https://github.com/bachmacintosh" target="_blank" rel="noopener noreferrer">Collin Bachman</a></li>
<li><a href="https://github.com/thuchede" target="_blank" rel="noopener noreferrer">Thomas Huchedé</a></li>
<li><a href="https://github.com/yepitschunked" target="_blank" rel="noopener noreferrer">Victor Lin</a></li>
<li><a href="https://github.com/y-hsgw" target="_blank" rel="noopener noreferrer">Yukihiro Hasegawa</a></li>
</ul>
</li>
<li>Members of the TypeScript team who helped with performance issues:<!-- -->
<ul>
<li><a href="https://github.com/DanielRosenwasser" target="_blank" rel="noopener noreferrer">Daniel Rosenwasser</a></li>
<li><a href="https://github.com/jakebailey" target="_blank" rel="noopener noreferrer">Jake Bailey</a></li>
<li><a href="https://github.com/sheetalkamat" target="_blank" rel="noopener noreferrer">Sheetal Nandi</a></li>
</ul>
</li>
</ul>
<p>See the <a href="https://github.com/typescript-eslint/typescript-eslint/milestone/9" target="_blank" rel="noopener noreferrer">v8.0.0 milestone</a> for the list of issues and associated merged pull requests.</p>
<h2 class="anchor anchorWithStickyNavbar_eAos" id="supporting-typescript-eslint">Supporting typescript-eslint<a href="https://typescript-eslint.io/blog/announcing-typescript-eslint-v8-beta#supporting-typescript-eslint" class="hash-link" aria-label="Direct link to Supporting typescript-eslint" title="Direct link to Supporting typescript-eslint">​</a></h2>
<p>If you enjoyed this blog post and/or use typescript-eslint, please consider <a href="https://opencollective.com/typescript-eslint" target="_blank" rel="noopener noreferrer">supporting us on Open Collective</a>. We're a small volunteer team and could use your support to make the ESLint experience on TypeScript great. Thanks! 💖</p>]]></content:encoded>
            <category>breaking changes</category>
            <category>typescript-eslint</category>
            <category>v7</category>
            <category>v8</category>
        </item>
        <item>
            <title><![CDATA[Changes to `consistent-type-imports` with Legacy Decorators and Decorator Metadata]]></title>
            <link>https://typescript-eslint.io/blog/changes-to-consistent-type-imports-with-decorators</link>
            <guid>https://typescript-eslint.io/blog/changes-to-consistent-type-imports-with-decorators</guid>
            <pubDate>Mon, 25 Mar 2024 00:00:00 GMT</pubDate>
            <description><![CDATA[Changes to consistent-type-imports when used with decorators, experimentalDecorators, and emitDecoratorMetadata]]></description>
            <content:encoded><![CDATA[<p>We've made some changes to the <a href="https://typescript-eslint.io/rules/consistent-type-imports"><code>consistent-type-imports</code> rule</a> to fix some long-standing issues when used alongside <code>experimentalDecorators: true</code> and <code>emitDecoratorMetadata: true</code>. These changes increase safety and prevent invalid fixes when using decorator metadata.</p>
<h2 class="anchor anchorWithStickyNavbar_eAos" id="experimental-decorator-metadata">Experimental Decorator Metadata<a href="https://typescript-eslint.io/blog/changes-to-consistent-type-imports-with-decorators#experimental-decorator-metadata" class="hash-link" aria-label="Direct link to Experimental Decorator Metadata" title="Direct link to Experimental Decorator Metadata">​</a></h2>
<p>TypeScript's <a href="https://aka.ms/tsconfig#experimentalDecorators" target="_blank" rel="noopener noreferrer"><code>experimentalDecorators</code> compiler option</a> (referred to as "legacy decorators" from here on) turns on support for an old version of the <a href="https://github.com/tc39/proposal-decorators" target="_blank" rel="noopener noreferrer">JavaScript TC39 decorator proposal</a> that was never standardized. TypeScript's legacy decorators are similar to the current proposal, but differ in that they use <a href="https://rbuckton.github.io/reflect-metadata/" target="_blank" rel="noopener noreferrer">metadata reflection</a> when TypeScript's <a href="https://aka.ms/tsconfig#emitDecoratorMetadata" target="_blank" rel="noopener noreferrer"><code>emitDecoratorMetadata</code> compiler option</a> is turned on.</p>
<p>When using legacy decorators with decorator metadata and a class is annotated with decorators, TypeScript will emit runtime metadata for the class (see the example below). That decorator metadata will capture property types, method parameter types, and method return types. Decorator metadata provides a bridge between the types (which are not available at compile time) and the runtime code.</p>
<p>The downside of generating this runtime code that it is derived using type information: meaning that the runtime code emitted changes based on the cross-file type information that TypeScript has computed. Doing so violates a key <a href="https://github.com/microsoft/TypeScript/wiki/TypeScript-Design-Goals" target="_blank" rel="noopener noreferrer">TypeScript design goal</a> of not changing runtime behavior based on type information.</p>
<p>To illustrate what this means consider the following snippet:</p>
<div class="language-ts codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockContent_m3Ux"><pre class="prism-code language-ts codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line"><span class="token keyword">import</span><span class="token plain"> Foo </span><span class="token keyword">from</span><span class="token plain"> </span><span class="token string">'foo'</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token keyword">import</span><span class="token plain"> decorator </span><span class="token keyword">from</span><span class="token plain"> </span><span class="token string">'decorator'</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token keyword">class</span><span class="token plain"> </span><span class="token class-name">Clazz</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token decorator at operator">@</span><span class="token decorator function">decorator</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token function">method</span><span class="token punctuation">(</span><span class="token plain">arg</span><span class="token operator">:</span><span class="token plain"> Foo</span><span class="token punctuation">)</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token punctuation">}</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>TypeScript will transpile this code to the following:</p>
<div class="language-ts codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockContent_m3Ux"><pre class="prism-code language-ts codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line"><span class="token keyword">import</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"> __decorate</span><span class="token punctuation">,</span><span class="token plain"> __metadata </span><span class="token punctuation">}</span><span class="token plain"> </span><span class="token keyword">from</span><span class="token plain"> </span><span class="token string">"tslib"</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token keyword">import</span><span class="token plain"> Foo </span><span class="token keyword">from</span><span class="token plain"> </span><span class="token string">'foo'</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token keyword">import</span><span class="token plain"> decorator </span><span class="token keyword">from</span><span class="token plain"> </span><span class="token string">'decorator'</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token keyword">class</span><span class="token plain"> </span><span class="token class-name">Clazz</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">    </span><span class="token function">method</span><span class="token punctuation">(</span><span class="token plain">arg</span><span class="token punctuation">)</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"> </span><span class="token punctuation">}</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token punctuation">}</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token function">__decorate</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">    decorator</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">    </span><span class="token function">__metadata</span><span class="token punctuation">(</span><span class="token string">"design:type"</span><span class="token punctuation">,</span><span class="token plain"> </span><span class="token builtin">Function</span><span class="token punctuation">)</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">    </span><span class="token function">__metadata</span><span class="token punctuation">(</span><span class="token string">"design:paramtypes"</span><span class="token punctuation">,</span><span class="token plain"> </span><span class="token comment">/* See below for what this value will be */</span><span class="token punctuation">)</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">    </span><span class="token function">__metadata</span><span class="token punctuation">(</span><span class="token string">"design:returntype"</span><span class="token punctuation">,</span><span class="token plain"> </span><span class="token keyword">void</span><span class="token plain"> </span><span class="token number">0</span><span class="token punctuation">)</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token punctuation">]</span><span class="token punctuation">,</span><span class="token plain"> Clazz</span><span class="token punctuation">.</span><span class="token plain">prototype</span><span class="token punctuation">,</span><span class="token plain"> </span><span class="token string">"method"</span><span class="token punctuation">,</span><span class="token plain"> </span><span class="token keyword">null</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>If the imported name <code>Foo</code> resolves to...</p>
<ul>
<li>a type then TS will emit <code>[Function]</code>, <code>[Object]</code>, <code>[String]</code>, <code>[Number]</code>, or <code>[Boolean]</code> depending on what that type resolves to.</li>
<li>an enum then TS will emit one of <code>[String]</code>, <code>[Number]</code>, or <code>[Object]</code> depending on the type of the enum's members<!-- -->
<ul>
<li><code>[Object]</code> is used for an enum that has both string and number values.</li>
</ul>
</li>
<li>a class declaration:<!-- -->
<ul>
<li>and the import <strong><em>is NOT</em></strong> annotated as <code>import type</code> then TS will emit <code>[Foo]</code>.</li>
<li>and the import <strong><em>IS</em></strong> annotated as <code>import type</code> then TS will emit <code>[Function]</code>.</li>
</ul>
</li>
</ul>
<p>In addition to requiring runtime type information, those metadata emit rules are confusing for developers to reason about.
They necessitate understanding edge cases specific to TypeScript's handling of decorators and type information.</p>
<h2 class="anchor anchorWithStickyNavbar_eAos" id="consistent-type-imports-caused-runtime-breakage"><code>consistent-type-imports</code> caused runtime breakage<a href="https://typescript-eslint.io/blog/changes-to-consistent-type-imports-with-decorators#consistent-type-imports-caused-runtime-breakage" class="hash-link" aria-label="Direct link to consistent-type-imports-caused-runtime-breakage" title="Direct link to consistent-type-imports-caused-runtime-breakage">​</a></h2>
<p>The important piece is that last dot point above - the handling of imported names that resolve to class declarations. If the import is not annotated as <code>import type</code> then TS emits a runtime reference to the imported name. This runtime reference is implicit and requires type information to derive - you cannot derive its existence purely based on single-file AST analysis.</p>
<p>The <a href="https://typescript-eslint.io/rules/consistent-type-imports"><code>consistent-type-imports</code> rule</a> was introduced to allow users to enforce that any imported names are annotated as <code>import type</code> if they are not used in a value location. How the rule makes this decision is based solely on the single file it's looking at. But another way the rule does not use any type information from TS and instead it scans the code using a technique called "scope analysis" so that it can find all references to the imported names and determine if each reference is a value reference.</p>
<div class="theme-admonition theme-admonition-tip admonition_pzuZ alert alert--success"><div class="admonitionHeading_uJho"><span class="admonitionIcon_vMH2"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>tip</div><div class="admonitionContent_gazR"><p>See <a href="https://typescript-eslint.io/blog/asts-and-typescript-eslint">ASTs and typescript-eslint</a> to understand how rules look at the syntax of files.</p></div></div>
<p>The issue arises with legacy decorators and decorator metadata - syntactically the only reference to <code>Foo</code> is a type reference. However the emitted code contains a hidden reference to <code>Foo</code>. When the rule relies upon the code it sees then it will report an error and attempt to mark <code>Foo</code> as <code>import type</code>. If the user applies this fix then that will cause their runtime code to change (<code>arg</code>'s metadata goes from <code>Foo</code> to <code>Function</code>) which can have downstream runtime impacts and cause broken code!</p>
<h2 class="anchor anchorWithStickyNavbar_eAos" id="past-broken-solution">Past (Broken) Solution<a href="https://typescript-eslint.io/blog/changes-to-consistent-type-imports-with-decorators#past-broken-solution" class="hash-link" aria-label="Direct link to Past (Broken) Solution" title="Direct link to Past (Broken) Solution">​</a></h2>
<p>In the past we tried to solve this problem by enforcing that imported names that are used in decorator metadata are specifically <em>not</em> marked as type-only imports to ensure that values are always correctly emitted in the runtime code.</p>
<p>However this solution had a hidden pitfall; if the user also used <code>isolatedModules: true</code> then TS will enforce that all imported types are explicitly marked as <code>import type</code> for compatibility with single-file build tools. This lead to an unresolvable situation where <code>consistent-type-imports</code> would enforce that an imported name <em>must not be</em> marked with <code>import type</code> so that we could ensure we don't break decorator metadata, and simultaneously TS would enforce that that same imported name <em>must be</em> marked with <code>import type</code>.</p>
<p>There have been a few attempts to fix this issue but the resolution we came to was that the only solution was to add type information to the rule so that it could correctly understand all of the above type-aware constraints. Adding type information to an existing rule is something we try to avoid because it is a major breaking change that restricts the rule to just users that leverage <a href="https://typescript-eslint.io/getting-started/typed-linting">type-aware linting</a>.</p>
<p>Adding type-information to the rule to handle this edge case would not be a positive change for users or the ecosystem:</p>
<ol>
<li>Many users are unable to configure typed linting and/or unwilling to take its performance hit. Requiring <a href="https://typescript-eslint.io/getting-started/typed-linting">type-aware linting</a> linting for this rule to serve a very small subset of impacted users would reduce the linting ability of many more un-impacted users.</li>
<li>It requires a specific combinations of compiler options to trigger it means that not everyone is impacted by the problem - so we'd be preventing a lot of un-impacted users from using the rule.</li>
<li>With the release of <a href="https://www.typescriptlang.org/docs/handbook/release-notes/typescript-5-0.html#decorators" target="_blank" rel="noopener noreferrer">TypeScript v5.0 and its stable decorators</a> <code>experimentalDecorators</code> are now the legacy syntax. Whilst <a href="https://www.typescriptlang.org/docs/handbook/release-notes/typescript-5-2.html#decorator-metadata" target="_blank" rel="noopener noreferrer">TypeScript v5.2 added support for the latest stable decorator metadata proposal</a> this proposal does not include type metadata - so it doesn't suffer the same drawbacks as its legacy counterpart.</li>
</ol>
<h2 class="anchor anchorWithStickyNavbar_eAos" id="todays-solution---the-compromise">Today's Solution - the Compromise<a href="https://typescript-eslint.io/blog/changes-to-consistent-type-imports-with-decorators#todays-solution---the-compromise" class="hash-link" aria-label="Direct link to Today's Solution - the Compromise" title="Direct link to Today's Solution - the Compromise">​</a></h2>
<p>Ultimately we determined the best solution was to just opt-out of handling this use-case entirely. This means that we can avoid accidentally reporting the wrong thing and fixing to code that either fails to compile or alters the emitted runtime metadata.</p>
<p>Now, if you have <strong>both</strong> <code>experimentalDecorators: true</code> and <code>emitDecoratorMetadata: true</code>, then the <code>consistent-type-imports</code> rule will <strong><em>not</em></strong> report any errors within any files <em>that contain decorators</em>.</p>
<p>All files without decorators will continue to report as expected. Similarly all projects that use <code>experimentalDecorators: false</code> and/or <code>emitDecoratorMetadata: false</code> will continue to report as expected.</p>
<h3 class="anchor anchorWithStickyNavbar_eAos" id="configuring-the-linter-to-expect-experimentaldecorators-true-and-emitdecoratormetadata-true">Configuring the linter to expect <code>experimentalDecorators: true</code> and <code>emitDecoratorMetadata: true</code><a href="https://typescript-eslint.io/blog/changes-to-consistent-type-imports-with-decorators#configuring-the-linter-to-expect-experimentaldecorators-true-and-emitdecoratormetadata-true" class="hash-link" aria-label="Direct link to configuring-the-linter-to-expect-experimentaldecorators-true-and-emitdecoratormetadata-true" title="Direct link to configuring-the-linter-to-expect-experimentaldecorators-true-and-emitdecoratormetadata-true">​</a></h3>
<p>If you are using <a href="https://typescript-eslint.io/getting-started/typed-linting">type-aware linting</a> then we will automatically infer your setup from your tsconfig and you should not need to configure anything manually.</p>
<p>Otherwise you can explicitly tell our tooling to analyze your code as if the compiler option was turned on by setting both <a href="https://typescript-eslint.io/packages/parser/#emitdecoratormetadata"><code>parserOptions.emitDecoratorMetadata = true</code></a> and <a href="https://typescript-eslint.io/packages/parser/#experimentaldecorators"><code>parserOptions.experimentalDecorators = true</code></a>. For example:</p>
<div class="language-js codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockTitle_P25_">eslint.config.js</div><div class="codeBlockContent_m3Ux"><pre class="prism-code language-js codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line"><span class="token keyword module">import</span><span class="token plain"> </span><span class="token imports">tseslint</span><span class="token plain"> </span><span class="token keyword module">from</span><span class="token plain"> </span><span class="token string">'typescript-eslint'</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token keyword module">export</span><span class="token plain"> </span><span class="token keyword module">default</span><span class="token plain"> tseslint</span><span class="token punctuation">.</span><span class="token method function property-access">config</span><span class="token punctuation">(</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token spread operator">...</span><span class="token plain">tseslint</span><span class="token punctuation">.</span><span class="token property-access">configs</span><span class="token punctuation">.</span><span class="token property-access">recommended</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">    </span><span class="token literal-property property">languageOptions</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">      </span><span class="token literal-property property">parserOptions</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">        </span><span class="token literal-property property">emitDecoratorMetadata</span><span class="token operator">:</span><span class="token plain"> </span><span class="token boolean">true</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">        </span><span class="token literal-property property">experimentalDecorators</span><span class="token operator">:</span><span class="token plain"> </span><span class="token boolean">true</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">      </span><span class="token punctuation">}</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">    </span><span class="token punctuation">}</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token punctuation">}</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token punctuation">)</span><span class="token punctuation">;</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<h2 class="anchor anchorWithStickyNavbar_eAos" id="alternatives-for-impacted-users">Alternatives for Impacted Users<a href="https://typescript-eslint.io/blog/changes-to-consistent-type-imports-with-decorators#alternatives-for-impacted-users" class="hash-link" aria-label="Direct link to Alternatives for Impacted Users" title="Direct link to Alternatives for Impacted Users">​</a></h2>
<p>If you are working in a workspace that is impacted by this change and want to correctly have your imports consistently marked with <code>type</code>, we suggest using the <a href="https://www.typescriptlang.org/tsconfig#verbatimModuleSyntax" target="_blank" rel="noopener noreferrer"><code>verbatimModuleSyntax</code></a> compiler option which will use type information to correctly enforce that types are marked with <code>type</code> and values are not when they are used in decorator metadata.</p>
<h2 class="anchor anchorWithStickyNavbar_eAos" id="supporting-typescript-eslint">Supporting typescript-eslint<a href="https://typescript-eslint.io/blog/changes-to-consistent-type-imports-with-decorators#supporting-typescript-eslint" class="hash-link" aria-label="Direct link to Supporting typescript-eslint" title="Direct link to Supporting typescript-eslint">​</a></h2>
<p>If you enjoyed this blog post and/or use typescript-eslint, please consider <a href="https://opencollective.com/typescript-eslint" target="_blank" rel="noopener noreferrer">supporting us on Open Collective</a>. We're a small volunteer team and could use your support to make the ESLint experience on TypeScript great. Thanks! 💖</p>]]></content:encoded>
            <category>consistent-type-imports</category>
            <category>experimentalDecorators</category>
            <category>emitDecoratorMetadata</category>
            <category>typescript-eslint</category>
        </item>
        <item>
            <title><![CDATA[Announcing typescript-eslint v7]]></title>
            <link>https://typescript-eslint.io/blog/announcing-typescript-eslint-v7</link>
            <guid>https://typescript-eslint.io/blog/announcing-typescript-eslint-v7</guid>
            <pubDate>Mon, 12 Feb 2024 00:00:00 GMT</pubDate>
            <description><![CDATA[Announcing the release of typescript-eslint's stable v7 release]]></description>
            <content:encoded><![CDATA[<p><a href="https://typescript-eslint.io/" target="_blank" rel="noopener noreferrer">typescript-eslint</a> is the tooling that enables standard JavaScript tools such as <a href="https://eslint.org/" target="_blank" rel="noopener noreferrer">ESLint</a> and <a href="https://prettier.io/" target="_blank" rel="noopener noreferrer">Prettier</a> to support TypeScript code.</p>
<p>We've been working on infrastructure improvements that will help ensuring long-term interoperability with other tools in the ecosystem. In particular this major release tightens our dependency requirements to help set us up for ESLint v9 and includes a new package <code>typescript-eslint</code> providing full support for flat config files!</p>
<h2 class="anchor anchorWithStickyNavbar_eAos" id="breaking-changes">Breaking Changes<a href="https://typescript-eslint.io/blog/announcing-typescript-eslint-v7#breaking-changes" class="hash-link" aria-label="Direct link to Breaking Changes" title="Direct link to Breaking Changes">​</a></h2>
<p>This is a small major release with just three breaking changes:</p>
<ol>
<li>Update Node.js engine requirement to <code>^18.18.0 || &gt;=20.0.0</code>. This means we are dropping support for Node 16, 19, and Node 18 versions prior to <code>18.18.0</code>. Note that this is the same requirement that ESLint v9 will impose.</li>
<li>Update the TypeScript peer dependency requirement to <code>&gt;=4.7.4</code>.</li>
<li>Update the ESLint peer dependency requirement to <code>^8.56.0</code>.</li>
</ol>
<p>For most users this means that an upgrade from v6 should just look like this:</p>
<div class="tabs-container tabList_hoTN"><ul role="tablist" aria-orientation="horizontal" class="tabs"><li role="tab" tabindex="0" aria-selected="true" class="tabs__item tabItem_dW3K tabs__item--active">npm</li><li role="tab" tabindex="-1" aria-selected="false" class="tabs__item tabItem_dW3K">Yarn</li><li role="tab" tabindex="-1" aria-selected="false" class="tabs__item tabItem_dW3K">pnpm</li></ul><div class="margin-top--md"><div role="tabpanel" class="tabItem_PzSZ"><div class="language-bash codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockContent_m3Ux"><pre class="prism-code language-bash codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line"><span class="token function">npm</span><span class="token plain"> i eslint typescript @typescript-eslint/parser @typescript-eslint/eslint-plugin</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div></div><div role="tabpanel" class="tabItem_PzSZ" hidden=""><div class="language-bash codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockContent_m3Ux"><pre class="prism-code language-bash codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line"><span class="token function">yarn</span><span class="token plain"> </span><span class="token function">add</span><span class="token plain"> eslint typescript @typescript-eslint/parser @typescript-eslint/eslint-plugin</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div></div><div role="tabpanel" class="tabItem_PzSZ" hidden=""><div class="language-bash codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockContent_m3Ux"><pre class="prism-code language-bash codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line"><span class="token function">pnpm</span><span class="token plain"> </span><span class="token function">add</span><span class="token plain"> eslint typescript @typescript-eslint/parser @typescript-eslint/eslint-plugin</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div></div></div></div>
<h3 class="anchor anchorWithStickyNavbar_eAos" id="into-the-future">Into the Future<a href="https://typescript-eslint.io/blog/announcing-typescript-eslint-v7#into-the-future" class="hash-link" aria-label="Direct link to Into the Future" title="Direct link to Into the Future">​</a></h3>
<p>The intent behind this release is for us to constrain variance in our dependencies to help set us up for the future. The upcoming ESLint v9 release will contain many API removals - all of which had replacements added in some of the latest ESLint v8 releases. By enforcing that you have the latest ESLint v8 release we ensure that you have the replacement APIs. This significantly reduces our maintenance burden and should mean we can release v9 support sooner and with less pain and effort.</p>
<h2 class="anchor anchorWithStickyNavbar_eAos" id="new-features---flat-config-support">New Features - Flat Config Support<a href="https://typescript-eslint.io/blog/announcing-typescript-eslint-v7#new-features---flat-config-support" class="hash-link" aria-label="Direct link to New Features - Flat Config Support" title="Direct link to New Features - Flat Config Support">​</a></h2>
<p>There is one big feature that's also shipping with this release:<br>
🎉 <strong><em>Official support for ESLint Flat Configs!</em></strong> 🎉</p>
<p>With v7 we're releasing a new package, <strong><code>typescript-eslint</code></strong>. This package can be imported within your <a href="https://eslint.org/docs/latest/use/configure/configuration-files-new" target="_blank" rel="noopener noreferrer">flat config</a> to access our configs, plugin, and parser. This package also exports a utility function called <code>config</code> which will allow you to write type-checked configuration files!</p>
<h3 class="anchor anchorWithStickyNavbar_eAos" id="switching-to-typescript-eslint">Switching to <code>typescript-eslint</code><a href="https://typescript-eslint.io/blog/announcing-typescript-eslint-v7#switching-to-typescript-eslint" class="hash-link" aria-label="Direct link to switching-to-typescript-eslint" title="Direct link to switching-to-typescript-eslint">​</a></h3>
<p>Because this new package includes dependencies on our plugin and parser, you can replace those dependencies entirely:</p>
<div class="tabs-container tabList_hoTN"><ul role="tablist" aria-orientation="horizontal" class="tabs"><li role="tab" tabindex="0" aria-selected="true" class="tabs__item tabItem_dW3K tabs__item--active">npm</li><li role="tab" tabindex="-1" aria-selected="false" class="tabs__item tabItem_dW3K">Yarn</li><li role="tab" tabindex="-1" aria-selected="false" class="tabs__item tabItem_dW3K">pnpm</li></ul><div class="margin-top--md"><div role="tabpanel" class="tabItem_PzSZ"><div class="language-bash codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockContent_m3Ux"><pre class="prism-code language-bash codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line"><span class="token function">npm</span><span class="token plain"> un @typescript-eslint/parser @typescript-eslint/eslint-plugin</span><br></span><span class="token-line"><span class="token plain"></span><span class="token function">npm</span><span class="token plain"> i typescript-eslint</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div></div><div role="tabpanel" class="tabItem_PzSZ" hidden=""><div class="language-bash codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockContent_m3Ux"><pre class="prism-code language-bash codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line"><span class="token function">yarn</span><span class="token plain"> remove @typescript-eslint/parser @typescript-eslint/eslint-plugin</span><br></span><span class="token-line"><span class="token plain"></span><span class="token function">yarn</span><span class="token plain"> </span><span class="token function">add</span><span class="token plain"> typescript-eslint</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div></div><div role="tabpanel" class="tabItem_PzSZ" hidden=""><div class="language-bash codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockContent_m3Ux"><pre class="prism-code language-bash codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line"><span class="token function">pnpm</span><span class="token plain"> remove @typescript-eslint/parser @typescript-eslint/eslint-plugin</span><br></span><span class="token-line"><span class="token plain"></span><span class="token function">pnpm</span><span class="token plain"> </span><span class="token function">add</span><span class="token plain"> typescript-eslint</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div></div></div></div>
<p>The simplest of this new tooling would be the following which will enable the ESLint recommended config and our recommended config (including turning on our plugin and parser):</p>
<div class="language-js codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockTitle_P25_">eslint.config.js</div><div class="codeBlockContent_m3Ux"><pre class="prism-code language-js codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line"><span class="token comment">// @ts-check</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token keyword module">import</span><span class="token plain"> </span><span class="token imports">eslint</span><span class="token plain"> </span><span class="token keyword module">from</span><span class="token plain"> </span><span class="token string">'@eslint/js'</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token keyword module">import</span><span class="token plain"> </span><span class="token imports">tseslint</span><span class="token plain"> </span><span class="token keyword module">from</span><span class="token plain"> </span><span class="token string">'typescript-eslint'</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token keyword module">export</span><span class="token plain"> </span><span class="token keyword module">default</span><span class="token plain"> tseslint</span><span class="token punctuation">.</span><span class="token method function property-access">config</span><span class="token punctuation">(</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  eslint</span><span class="token punctuation">.</span><span class="token property-access">configs</span><span class="token punctuation">.</span><span class="token property-access">recommended</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token spread operator">...</span><span class="token plain">tseslint</span><span class="token punctuation">.</span><span class="token property-access">configs</span><span class="token punctuation">.</span><span class="token property-access">recommended</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token punctuation">)</span><span class="token punctuation">;</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>If you're into having a bit more control then you can also declare our plugin and parser in your config - both are exported from this package! For example this config would enable our plugin, our parser, and type-aware linting with a few of our popular type-aware rules:</p>
<div class="language-js codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockTitle_P25_">eslint.config.js</div><div class="codeBlockContent_m3Ux"><pre class="prism-code language-js codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line"><span class="token comment">// @ts-check</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token keyword module">import</span><span class="token plain"> </span><span class="token imports">tseslint</span><span class="token plain"> </span><span class="token keyword module">from</span><span class="token plain"> </span><span class="token string">'typescript-eslint'</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token keyword module">export</span><span class="token plain"> </span><span class="token keyword module">default</span><span class="token plain"> tseslint</span><span class="token punctuation">.</span><span class="token method function property-access">config</span><span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token literal-property property">plugins</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">    </span><span class="token string-property property">'@typescript-eslint'</span><span class="token operator">:</span><span class="token plain"> tseslint</span><span class="token punctuation">.</span><span class="token property-access">plugin</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token punctuation">}</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token literal-property property">languageOptions</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">    </span><span class="token literal-property property">parser</span><span class="token operator">:</span><span class="token plain"> tseslint</span><span class="token punctuation">.</span><span class="token property-access">parser</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">    </span><span class="token literal-property property">parserOptions</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">      </span><span class="token literal-property property">project</span><span class="token operator">:</span><span class="token plain"> </span><span class="token boolean">true</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">    </span><span class="token punctuation">}</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token punctuation">}</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token literal-property property">rules</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">    </span><span class="token string-property property">'@typescript-eslint/no-unsafe-argument'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">    </span><span class="token string-property property">'@typescript-eslint/no-unsafe-assignment'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">    </span><span class="token string-property property">'@typescript-eslint/no-unsafe-call'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">    </span><span class="token string-property property">'@typescript-eslint/no-unsafe-member-access'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">    </span><span class="token string-property property">'@typescript-eslint/no-unsafe-return'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token punctuation">}</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>You don't have to use this package if you haven't yet migrated to flat configs.
But once you do, this is our recommend way to set up our tooling.</p>
<p>For more information check out:</p>
<ul>
<li><a href="https://eslint.org/docs/latest/use/configure/configuration-files-new" target="_blank" rel="noopener noreferrer">ESLint's docs on flat configs</a></li>
<li><a href="https://eslint.org/docs/latest/use/configure/migration-guide" target="_blank" rel="noopener noreferrer">ESLint's docs on migrating to flat configs</a></li>
<li><a href="https://typescript-eslint.io/packages/typescript-eslint">The <code>typescript-eslint</code> package documentation</a></li>
</ul>
<h2 class="anchor anchorWithStickyNavbar_eAos" id="supporting-typescript-eslint">Supporting typescript-eslint<a href="https://typescript-eslint.io/blog/announcing-typescript-eslint-v7#supporting-typescript-eslint" class="hash-link" aria-label="Direct link to Supporting typescript-eslint" title="Direct link to Supporting typescript-eslint">​</a></h2>
<p>If you enjoyed this blog post and/or use typescript-eslint, please consider <a href="https://opencollective.com/typescript-eslint" target="_blank" rel="noopener noreferrer">supporting us on Open Collective</a>. We're a small volunteer team and could use your support to make the ESLint experience on TypeScript great. Thanks! 💖</p>]]></content:encoded>
            <category>breaking changes</category>
            <category>typescript-eslint</category>
            <category>v6</category>
            <category>v7</category>
            <category>flat configs</category>
        </item>
        <item>
            <title><![CDATA[Deprecating Formatting Rules]]></title>
            <link>https://typescript-eslint.io/blog/deprecating-formatting-rules</link>
            <guid>https://typescript-eslint.io/blog/deprecating-formatting-rules</guid>
            <pubDate>Mon, 25 Dec 2023 00:00:00 GMT</pubDate>
            <description><![CDATA[We're following ESLint's lead in moving our formatting lint rules to the ESLint Stylistic project.]]></description>
            <content:encoded><![CDATA[<p><a href="https://eslint.org/blog/2023/10/deprecating-formatting-rules" target="_blank" rel="noopener noreferrer">ESLint recently announced their plan to deprecate their core formatting rules</a>.
The <a href="https://eslint.style/" target="_blank" rel="noopener noreferrer">ESLint Stylistic</a> project has taken over maintenance of formatting rules.</p>
<p>As a result, we in typescript-eslint are now able to deprecate our formatting rules as well.
We'll keep these deprecated rules available until our next major version.</p>
<h2 class="anchor anchorWithStickyNavbar_eAos" id="context-formatting-rules">Context: Formatting Rules<a href="https://typescript-eslint.io/blog/deprecating-formatting-rules#context-formatting-rules" class="hash-link" aria-label="Direct link to Context: Formatting Rules" title="Direct link to Context: Formatting Rules">​</a></h2>
<p>The ESLint blog post thoroughly explains the history and tradeoffs of formatting rules.
See also <a href="https://eslint.org/blog/2020/05/changes-to-rules-policies/#what-are-the-changes" target="_blank" rel="noopener noreferrer">ESLint's 2020 Changes to Rule Policies blog post</a> and our <em><a href="https://typescript-eslint.io/users/what-about-formatting">What About Formatting?</a></em> docs.
The performance downsides of formatting rules are heightened when <a href="https://typescript-eslint.io/getting-started/typed-linting">linting with type information</a>.</p>
<h2 class="anchor anchorWithStickyNavbar_eAos" id="timelines">Timelines<a href="https://typescript-eslint.io/blog/deprecating-formatting-rules#timelines" class="hash-link" aria-label="Direct link to Timelines" title="Direct link to Timelines">​</a></h2>
<p><a href="https://github.com/typescript-eslint/typescript-eslint/releases/tag/v6.16.0" target="_blank" rel="noopener noreferrer">v6.16.0</a>, released December 25th, 2023, marks the rules as deprecated.
Deprecation is only a documentation change.
Per semantic versioning, formatting-related rules will remain available for all releases of typescript-eslint in the current major version, v6.</p>
<p><strong>Our next major version, v7, will remove all deprecated rules.</strong></p>
<div class="theme-admonition theme-admonition-note admonition_pzuZ alert alert--secondary"><div class="admonitionHeading_uJho"><span class="admonitionIcon_vMH2"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>note</div><div class="admonitionContent_gazR"><p>The <a href="https://typescript-eslint.io/users/configs#stylistic"><code>stylistic</code> configurations</a> 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.</p></div></div>
<h2 class="anchor anchorWithStickyNavbar_eAos" id="upgrading-to-eslint-stylistic">Upgrading to ESLint Stylistic<a href="https://typescript-eslint.io/blog/deprecating-formatting-rules#upgrading-to-eslint-stylistic" class="hash-link" aria-label="Direct link to Upgrading to ESLint Stylistic" title="Direct link to Upgrading to ESLint Stylistic">​</a></h2>
<p>Although you can continue to use formatting rules in typescript-eslint for now, we don't plan on adding any new features or fixes to the rules.
You'll want to switch to using their equivalents from <a href="https://eslint.style/" target="_blank" rel="noopener noreferrer">ESLint Stylistic</a>.</p>
<p>See the <a href="https://eslint.style/guide/getting-started" target="_blank" rel="noopener noreferrer">ESLint Stylistic &gt; Getting Started</a> guide for how to switch formatting rules to that project.
The equivalent stylistic rules for deprecated typescript-eslint rules are summarized in this table:</p>
<table><thead><tr><th>typescript-eslint Rule</th><th>ESLint Stylistic Rule</th></tr></thead><tbody><tr><td><a href="https://typescript-eslint.io/rules/block-spacing"><code>@typescript-eslint/block-spacing</code></a></td><td><a href="https://eslint.style/rules/ts/block-spacing" target="_blank" rel="noopener noreferrer"><code>@stylistic/block-spacing</code></a></td></tr><tr><td><a href="https://typescript-eslint.io/rules/brace-style"><code>@typescript-eslint/brace-style</code></a></td><td><a href="https://eslint.style/rules/ts/brace-style" target="_blank" rel="noopener noreferrer"><code>@stylistic/brace-style</code></a></td></tr><tr><td><a href="https://typescript-eslint.io/rules/comma-dangle"><code>@typescript-eslint/comma-dangle</code></a></td><td><a href="https://eslint.style/rules/ts/comma-dangle" target="_blank" rel="noopener noreferrer"><code>@stylistic/comma-dangle</code></a></td></tr><tr><td><a href="https://typescript-eslint.io/rules/comma-spacing"><code>@typescript-eslint/comma-spacing</code></a></td><td><a href="https://eslint.style/rules/ts/comma-spacing" target="_blank" rel="noopener noreferrer"><code>@stylistic/comma-spacing</code></a></td></tr><tr><td><a href="https://typescript-eslint.io/rules/func-call-spacing"><code>@typescript-eslint/func-call-spacing</code></a></td><td><a href="https://eslint.style/rules/ts/func-call-spacing" target="_blank" rel="noopener noreferrer"><code>@stylistic/func-call-spacing</code></a></td></tr><tr><td><a href="https://typescript-eslint.io/rules/indent"><code>@typescript-eslint/indent</code></a></td><td><a href="https://eslint.style/rules/ts/indent" target="_blank" rel="noopener noreferrer"><code>@stylistic/indent</code></a></td></tr><tr><td><a href="https://typescript-eslint.io/rules/key-spacing"><code>@typescript-eslint/key-spacing</code></a></td><td><a href="https://eslint.style/rules/ts/key-spacing" target="_blank" rel="noopener noreferrer"><code>@stylistic/key-spacing</code></a></td></tr><tr><td><a href="https://typescript-eslint.io/rules/keyword-spacing"><code>@typescript-eslint/keyword-spacing</code></a></td><td><a href="https://eslint.style/rules/ts/keyword-spacing" target="_blank" rel="noopener noreferrer"><code>@stylistic/keyword-spacing</code></a></td></tr><tr><td><a href="https://typescript-eslint.io/rules/lines-around-comment"><code>@typescript-eslint/lines-around-comment</code></a></td><td><a href="https://eslint.style/rules/ts/lines-around-comment" target="_blank" rel="noopener noreferrer"><code>@stylistic/lines-around-comment</code></a></td></tr><tr><td><a href="https://typescript-eslint.io/rules/lines-between-class-members"><code>@typescript-eslint/lines-between-class-members</code></a></td><td><a href="https://eslint.style/rules/ts/lines-between-class-members" target="_blank" rel="noopener noreferrer"><code>@stylistic/lines-between-class-members</code></a></td></tr><tr><td><a href="https://typescript-eslint.io/rules/member-delimiter-style"><code>@typescript-eslint/member-delimiter-style</code></a></td><td><a href="https://eslint.style/rules/ts/member-delimiter-style" target="_blank" rel="noopener noreferrer"><code>@stylistic/member-delimiter-style</code></a></td></tr><tr><td><a href="https://typescript-eslint.io/rules/no-extra-parens"><code>@typescript-eslint/no-extra-parens</code></a></td><td><a href="https://eslint.style/rules/ts/no-extra-parens" target="_blank" rel="noopener noreferrer"><code>@stylistic/no-extra-parens</code></a></td></tr><tr><td><a href="https://typescript-eslint.io/rules/no-extra-semi"><code>@typescript-eslint/no-extra-semi</code></a></td><td><a href="https://eslint.style/rules/ts/no-extra-semi" target="_blank" rel="noopener noreferrer"><code>@stylistic/no-extra-semi</code></a></td></tr><tr><td><a href="https://typescript-eslint.io/rules/padding-line-between-statements"><code>@typescript-eslint/padding-line-between-statements</code></a></td><td><a href="https://eslint.style/rules/ts/padding-line-between-statements" target="_blank" rel="noopener noreferrer"><code>@stylistic/padding-line-between-statements</code></a></td></tr><tr><td><a href="https://typescript-eslint.io/rules/quotes"><code>@typescript-eslint/quotes</code></a></td><td><a href="https://eslint.style/rules/ts/quotes" target="_blank" rel="noopener noreferrer"><code>@stylistic/quotes</code></a></td></tr><tr><td><a href="https://typescript-eslint.io/rules/semi"><code>@typescript-eslint/semi</code></a></td><td><a href="https://eslint.style/rules/ts/semi" target="_blank" rel="noopener noreferrer"><code>@stylistic/semi</code></a></td></tr><tr><td><a href="https://typescript-eslint.io/rules/space-before-blocks"><code>@typescript-eslint/space-before-blocks</code></a></td><td><a href="https://eslint.style/rules/ts/space-before-blocks" target="_blank" rel="noopener noreferrer"><code>@stylistic/space-before-blocks</code></a></td></tr><tr><td><a href="https://typescript-eslint.io/rules/space-before-function-paren"><code>@typescript-eslint/space-before-function-paren</code></a></td><td><a href="https://eslint.style/rules/ts/space-before-function-paren" target="_blank" rel="noopener noreferrer"><code>@stylistic/space-before-function-paren</code></a></td></tr><tr><td><a href="https://typescript-eslint.io/rules/space-infix-ops"><code>@typescript-eslint/space-infix-ops</code></a></td><td><a href="https://eslint.style/rules/ts/space-infix-ops" target="_blank" rel="noopener noreferrer"><code>@stylistic/space-infix-ops</code></a></td></tr><tr><td><a href="https://typescript-eslint.io/rules/type-annotation-spacing"><code>@typescript-eslint/type-annotation-spacing</code></a></td><td><a href="https://eslint.style/rules/ts/type-annotation-spacing" target="_blank" rel="noopener noreferrer"><code>@stylistic/type-annotation-spacing</code></a></td></tr></tbody></table>
<h2 class="anchor anchorWithStickyNavbar_eAos" id="supporting-typescript-eslint">Supporting typescript-eslint<a href="https://typescript-eslint.io/blog/deprecating-formatting-rules#supporting-typescript-eslint" class="hash-link" aria-label="Direct link to Supporting typescript-eslint" title="Direct link to Supporting typescript-eslint">​</a></h2>
<p>If you enjoyed this blog post and/or use typescript-eslint, please consider <a href="https://opencollective.com/typescript-eslint" target="_blank" rel="noopener noreferrer">supporting us on Open Collective</a>. We're a small volunteer team and could use your support to make the ESLint experience on TypeScript great. Thanks! 💖</p>]]></content:encoded>
            <category>formatter</category>
            <category>formatting</category>
            <category>prettier</category>
            <category>style</category>
            <category>stylistic</category>
        </item>
        <item>
            <title><![CDATA[Relative TSConfig Projects with `parserOptions.project = true`]]></title>
            <link>https://typescript-eslint.io/blog/parser-options-project-true</link>
            <guid>https://typescript-eslint.io/blog/parser-options-project-true</guid>
            <pubDate>Mon, 18 Sep 2023 00:00:00 GMT</pubDate>
            <description><![CDATA[Simplifying how many projects resolve their]]></description>
            <content:encoded><![CDATA[<p><a href="https://typescript-eslint.io/getting-started/typed-linting">"Typed linting"</a>, 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 <code>tsconfig.json</code> 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.</p>
<p>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 <code>parserOptions.project</code> equal to <code>true</code> in ESLint configurations.</p>
<p>This post will explain what life was like before, what's changed, and what's coming next. 🎉</p>
<h2 class="anchor anchorWithStickyNavbar_eAos" id="the-problem-with-projects">The Problem With Projects<a href="https://typescript-eslint.io/blog/parser-options-project-true#the-problem-with-projects" class="hash-link" aria-label="Direct link to The Problem With Projects" title="Direct link to The Problem With Projects">​</a></h2>
<p>The <code>@typescript-eslint/parser</code> package is what enables ESLint to parse TypeScript source files.
It converts raw TypeScript code into an <a href="https://typescript-eslint.io/blog/asts-and-typescript-eslint">"AST" format</a>.
When <a href="https://typescript-eslint.io/packages/parser#project"><code>parserOptions.project</code></a> is specified, it additionally sets up TypeScript programs that can be used by <a href="https://typescript-eslint.io/developers/custom-rules#typed-rules">typed rules</a>.</p>
<p>Many projects today start with ESLint configs that look something like:</p>
<div class="language-js codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockContent_m3Ux"><pre class="prism-code language-js codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line"><span class="token plain">module</span><span class="token punctuation">.</span><span class="token property-access">exports</span><span class="token plain"> </span><span class="token operator">=</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token comment">// ...</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token literal-property property">parserOptions</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">    </span><span class="token literal-property property">project</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'./tsconfig.json'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">    </span><span class="token literal-property property">tsconfigRootDir</span><span class="token operator">:</span><span class="token plain"> __dirname</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token punctuation">}</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token comment">// ...</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token punctuation">}</span><span class="token punctuation">;</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>In larger repos, <code>parserOptions.project</code> often ends up being one of the three traditionally allowed forms:</p>
<ul>
<li>Path, such as <code>project: './tsconfig.json'</code></li>
<li>Glob pattern, such as <code>project: './packages/**/tsconfig.json'</code></li>
<li>Array of paths and/or glob patterns, such as <code>project: ['./packages/**/tsconfig.json', './separate-package/tsconfig.json']</code></li>
</ul>
<p>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:</p>
<ul>
<li>Particularly large repos can end up with so many TSConfig globs, they become confusing to developers or even cause <a href="https://typescript-eslint.io/troubleshooting/typed-linting/performance#wide-includes-in-your-eslint-options">performance issues from overly permissive globs</a></li>
<li>Needing to change a template ESLint config every time it's used for a different repository structure is a pain</li>
<li>Using a TSConfig that's different from what your editor uses can result in different lint reports between the editor and the command-line</li>
</ul>
<p>Although developers may sometimes need exact control over their <code>parserOptions.project</code>, most of the time we just want to use the <em>nearest <code>tsconfig.json</code> to each linted file</em>, which is the TSConfig used by the editor by default.</p>
<p>In other words, many developers want our <a href="https://github.com/typescript-eslint/typescript-eslint/issues/101" target="_blank" rel="noopener noreferrer">issue #101: Feature request: support looking up tsconfig.json relative to linted file</a>.</p>
<h2 class="anchor anchorWithStickyNavbar_eAos" id="introducing-true">Introducing <code>true</code><a href="https://typescript-eslint.io/blog/parser-options-project-true#introducing-true" class="hash-link" aria-label="Direct link to introducing-true" title="Direct link to introducing-true">​</a></h2>
<p>As of typescript-eslint 5.52.0, we now support providing <code>true</code> for <code>parserOptions.project</code>:</p>
<div class="language-js codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockContent_m3Ux"><pre class="prism-code language-js codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line"><span class="token plain">module</span><span class="token punctuation">.</span><span class="token property-access">exports</span><span class="token plain"> </span><span class="token operator">=</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token comment">// ...</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token literal-property property">parserOptions</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">    </span><span class="token literal-property property">project</span><span class="token operator">:</span><span class="token plain"> </span><span class="token boolean">true</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">    </span><span class="token literal-property property">tsconfigRootDir</span><span class="token operator">:</span><span class="token plain"> __dirname</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token punctuation">}</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token comment">// ...</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token punctuation">}</span><span class="token punctuation">;</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Doing so indicates that each source file being linted should use type information based on the nearest <code>tsconfig.json</code> in its directory.
For each file, <code>@typescript-eslint/parser</code> will check that file's directory, then the parent directory, and so on - until a <code>tsconfig.json</code> file is found.</p>
<div class="theme-admonition theme-admonition-tip admonition_pzuZ alert alert--success"><div class="admonitionHeading_uJho"><span class="admonitionIcon_vMH2"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>tip</div><div class="admonitionContent_gazR"><p>We recommend setting the <a href="https://typescript-eslint.io/packages/parser#tsconfigrootdir"><code>tsconfigRootDir</code></a> ESLint config to the project's root directory (most commonly, <code>__dirname</code>).
That way, if you accidentally delete or rename the root <code>tsconfig.json</code> file, <code>@typescript-eslint/parser</code> won't search parent directories for higher <code>tsconfig.json</code> files.</p></div></div>
<h3 class="anchor anchorWithStickyNavbar_eAos" id="why-try-true">Why Try <code>true</code><a href="https://typescript-eslint.io/blog/parser-options-project-true#why-try-true" class="hash-link" aria-label="Direct link to why-try-true" title="Direct link to why-try-true">​</a></h3>
<p>If your project uses typed linting and manually specifies <code>tsconfig.json</code> files, we'd highly recommend trying out <code>parserOptions.project: true</code>.
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. 🚀</p>
<p>In the long term, we're hoping to further improve the configuration and performance for typed linting (see <em><a href="https://typescript-eslint.io/blog/parser-options-project-true#project-services">Project Services</a></em> below).
Simplifying your configuration now will make it easier to onboard to our new options when they're available.</p>
<h3 class="anchor anchorWithStickyNavbar_eAos" id="how-it-works">How It Works<a href="https://typescript-eslint.io/blog/parser-options-project-true#how-it-works" class="hash-link" aria-label="Direct link to How It Works" title="Direct link to How It Works">​</a></h3>
<p>When <code>@typescript-eslint/parser</code> 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.</p>
<p>Depending on how the ESLint config's <code>parserOptions.project</code> was specified, determining <em>which</em> TSConfig file to use for each file can be different:</p>
<ul>
<li>For a single path (e.g. <code>"tsconfig.json"</code>), only one Program will be created, and all linted files will reuse it.</li>
<li>For globs and/or arrays (e.g. <code>"./packages/*/tsconfig.json"</code>), each linted file will use the Program created by the <em>first</em> matched TSConfig file.</li>
</ul>
<p>For <code>true</code>, each linted file will first try the <code>tsconfig.json</code> in its directory, then its parent directory, and so on until one is found on disk or the directory root (<code>parserOptions.tsconfigRootDir</code>) is reached.</p>
<div class="theme-admonition theme-admonition-note admonition_pzuZ alert alert--secondary"><div class="admonitionHeading_uJho"><span class="admonitionIcon_vMH2"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>note</div><div class="admonitionContent_gazR"><p><code>@typescript-eslint/parser</code> caches those directory <code>tsconfig.json</code> file lookups for a duration corresponding to <a href="https://typescript-eslint.io/packages/parser#cachelifetime"><code>parserOptions.cacheLifetime</code></a>.
No potential TSConfig path should be checked more than once in a lint run.</p></div></div>
<p>See <a href="https://github.com/typescript-eslint/typescript-eslint/pull/6084" target="_blank" rel="noopener noreferrer">feat(typescript-estree): allow specifying project: true</a> for the backing code changes.</p>
<h2 class="anchor anchorWithStickyNavbar_eAos" id="whats-next">What's Next<a href="https://typescript-eslint.io/blog/parser-options-project-true#whats-next" class="hash-link" aria-label="Direct link to What's Next" title="Direct link to What's Next">​</a></h2>
<h3 class="anchor anchorWithStickyNavbar_eAos" id="investigating-custom-tsconfig-names">Investigating Custom TSConfig Names<a href="https://typescript-eslint.io/blog/parser-options-project-true#investigating-custom-tsconfig-names" class="hash-link" aria-label="Direct link to Investigating Custom TSConfig Names" title="Direct link to Investigating Custom TSConfig Names">​</a></h3>
<p>Some projects use TSConfig files with names other than <code>tsconfig.json</code>: most commonly, <code>tsconfig.eslint.json</code>.
<code>parserOptions.project: true</code> does not support specifying different name(s) to search for.
We have two followup issues filed to investigate fleshing out that support:</p>
<ul>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/issues/7383" target="_blank" rel="noopener noreferrer">Enhancement: Allow altering the file names that project: true searches for</a></li>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/issues/7384" target="_blank" rel="noopener noreferrer">Enhancement: Allow parserOptions.project to be (true | string)[]?</a></li>
</ul>
<p>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!</p>
<h3 class="anchor anchorWithStickyNavbar_eAos" id="project-services">Project Services<a href="https://typescript-eslint.io/blog/parser-options-project-true#project-services" class="hash-link" aria-label="Direct link to Project Services" title="Direct link to Project Services">​</a></h3>
<p>The downside of having users specify <code>parserOptions.project</code> at all is that <code>@typescript-eslint/parser</code> needs manual logic to create TypeScript Programs and associate them with linted files.
Manual Program creation logic comes with a few issues:</p>
<ul>
<li>Complex project setups can be difficult to get right.<!-- -->
<ul>
<li>For example, <a href="https://github.com/typescript-eslint/typescript-eslint/issues/2094" target="_blank" rel="noopener noreferrer">typescript-eslint does not yet support Project References</a>.</li>
</ul>
</li>
<li>The TypeScript compiler options used in the user's editor might differ from the compiler options in the TSConfigs they specified on disk.</li>
<li>Files not included in created Programs can't be linted with type information, even though editors still typically surface type information when editing those files.<!-- -->
<ul>
<li>Most commonly, <code>.eslintrc.(c)js</code> files can be tricky to lint, resulting in the dreaded <a href="https://typescript-eslint.io/troubleshooting/typed-linting/performance#i-get-errors-telling-me-eslint-was-configured-to-run--however-that-tsconfig-does-not--none-of-those-tsconfigs-include-this-file"><em>TSConfig does not include this file</em> error</a>.</li>
</ul>
</li>
</ul>
<p>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 <code>project: true</code>), and will also allow type information to be computed for JavaScript files without the <code>allowJs</code> compiler option (unlike <code>project: true</code>).</p>
<p>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 <code>EXPERIMENTAL_</code> prefix for at least all of the <code>6.X</code> versions.</p>
<p>See <a href="https://typescript-eslint.io/packages/parser#experimental_useprojectservice">Packages &gt; Parser &gt; <code>EXPERIMENTAL_useProjectService</code></a> for more information.</p>
<h2 class="anchor anchorWithStickyNavbar_eAos" id="supporting-typescript-eslint">Supporting typescript-eslint<a href="https://typescript-eslint.io/blog/parser-options-project-true#supporting-typescript-eslint" class="hash-link" aria-label="Direct link to Supporting typescript-eslint" title="Direct link to Supporting typescript-eslint">​</a></h2>
<p>If you enjoyed this blog post and/or use typescript-eslint, please consider <a href="https://opencollective.com/typescript-eslint" target="_blank" rel="noopener noreferrer">supporting us on Open Collective</a>. We're a small volunteer team and could use your support to make the ESLint experience on TypeScript great. Thanks! 💖</p>]]></content:encoded>
            <category>parser</category>
            <category>parser options</category>
            <category>project</category>
            <category>tsconfig</category>
        </item>
        <item>
            <title><![CDATA[Announcing typescript-eslint v6]]></title>
            <link>https://typescript-eslint.io/blog/announcing-typescript-eslint-v6</link>
            <guid>https://typescript-eslint.io/blog/announcing-typescript-eslint-v6</guid>
            <pubDate>Sun, 09 Jul 2023 00:00:00 GMT</pubDate>
            <description><![CDATA[Announcing the release of typescript-eslint's stable v6 release, including its changes and timeline.]]></description>
            <content:encoded><![CDATA[<p><a href="https://typescript-eslint.io/" target="_blank" rel="noopener noreferrer">typescript-eslint</a> is the tooling that enables standard JavaScript tools such as <a href="https://eslint.org/" target="_blank" rel="noopener noreferrer">ESLint</a> and <a href="https://prettier.io/" target="_blank" rel="noopener noreferrer">Prettier</a> to support TypeScript code.
We've been working on a set of breaking changes and general features that we're excited to get released! 🎉</p>
<p>We'd previously blogged about v6 in <a href="https://typescript-eslint.io/blog/announcing-typescript-eslint-v6-beta">Announcing typescript-eslint v6 Beta</a>.
This blog post contains much of the same information as that one, but updated for changes made since the beta - including a few breaking changes.</p>
<blockquote>
<p>✨ indicates a change that was not present in the v6 beta.</p>
</blockquote>
<h2 class="anchor anchorWithStickyNavbar_eAos" id="using-v6">Using v6<a href="https://typescript-eslint.io/blog/announcing-typescript-eslint-v6#using-v6" class="hash-link" aria-label="Direct link to Using v6" title="Direct link to Using v6">​</a></h2>
<p>Whether you're new to linting your TypeScript code or a returning user, please do upgrade to the latest major version of typescript-eslint!
V6 comes with a suite of quality-of-life improvements we think you'll appreciate.</p>
<h3 class="anchor anchorWithStickyNavbar_eAos" id="as-a-new-user">As A New User<a href="https://typescript-eslint.io/blog/announcing-typescript-eslint-v6#as-a-new-user" class="hash-link" aria-label="Direct link to As A New User" title="Direct link to As A New User">​</a></h3>
<p>If you don't yet use typescript-eslint, you can go through our <a href="https://typescript-eslint.io/getting-started">configuration steps on the <em>Getting Started</em> docs</a>.
It'll walk you through setting up typescript-eslint in a project.</p>
<h3 class="anchor anchorWithStickyNavbar_eAos" id="as-an-existing-user">As An Existing User<a href="https://typescript-eslint.io/blog/announcing-typescript-eslint-v6#as-an-existing-user" class="hash-link" aria-label="Direct link to As An Existing User" title="Direct link to As An Existing User">​</a></h3>
<p>If you already use typescript-eslint, you'll need to first replace your package's previous versions of <code>@typescript-eslint/eslint-plugin</code> and <code>@typescript-eslint/parser</code> with the latest versions:</p>
<div class="language-shell codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockContent_m3Ux"><pre class="prism-code language-shell codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line"><span class="token function">npm</span><span class="token plain"> i @typescript-eslint/eslint-plugin@latest @typescript-eslint/parser@latest --save-dev</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>We highly recommend then basing your ESLint configuration on the reworked typescript-eslint <a href="https://typescript-eslint.io/blog/announcing-typescript-eslint-v6#reworked-configuration-names">recommended configurations mentioned later in this post</a> — especially if it's been a while since you've reworked your linter config.</p>
<h2 class="anchor anchorWithStickyNavbar_eAos" id="user-facing-breaking-changes">User-Facing Breaking Changes<a href="https://typescript-eslint.io/blog/announcing-typescript-eslint-v6#user-facing-breaking-changes" class="hash-link" aria-label="Direct link to User-Facing Breaking Changes" title="Direct link to User-Facing Breaking Changes">​</a></h2>
<p>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.</p>
<h3 class="anchor anchorWithStickyNavbar_eAos" id="reworked-configuration-names">Reworked Configuration Names<a href="https://typescript-eslint.io/blog/announcing-typescript-eslint-v6#reworked-configuration-names" class="hash-link" aria-label="Direct link to Reworked Configuration Names" title="Direct link to Reworked Configuration Names">​</a></h3>
<p>The biggest configuration change in typescript-eslint v6 is that we've reworked the names of our <a href="https://typescript-eslint.io/users/configs">provided user configuration files</a>.
typescript-eslint v5 provided three recommended configurations:</p>
<ul>
<li><a href="https://typescript-eslint.io/users/configs#recommended"><code>recommended</code></a>: Recommended rules for code correctness that you can drop in without additional configuration.</li>
<li><a href="https://typescript-eslint.io/users/configs#recommended-requiring-type-checking"><code>recommended-requiring-type-checking</code></a>: Additional recommended rules that require type information.</li>
<li><a href="https://typescript-eslint.io/users/configs#strict"><code>strict</code></a>: Additional strict rules that can also catch bugs but are more opinionated than recommended rules.</li>
</ul>
<p>Those configurations worked well for most projects.
However, some users correctly noted two flaws in that approach:</p>
<ul>
<li>Strict rules that didn't require type checking were lumped in with those that did.</li>
<li><em>Stylistic</em> best practices were lumped in with rules that actually find bugs.</li>
</ul>
<p>As a result, we've reworked the configurations provided by typescript-eslint into these two groups:</p>
<ul>
<li>Functional rule configurations, for best best practices and code correctness:<!-- -->
<ul>
<li><strong><code>recommended</code></strong>: Recommended rules that you can drop in without additional configuration.</li>
<li><strong><code>recommended-type-checked</code></strong>:&nbsp;Additional recommended rules that require type information.</li>
<li><strong><code>strict</code></strong>: Additional strict rules that can also catch bugs but are more opinionated than recommended rules <em>(without type information)</em>.</li>
<li><strong><code>strict-type-checked</code></strong>: Additional strict rules that do require type information.</li>
</ul>
</li>
<li>Stylistic rule configurations, for consistent and predictable syntax usage:<!-- -->
<ul>
<li><strong><code>stylistic</code></strong>: Stylistic rules you can drop in without additional configuration.</li>
<li><strong><code>stylistic-type-checked</code></strong>: Additional stylistic rules that require type information.</li>
</ul>
</li>
</ul>
<blockquote>
<p><code>recommended-requiring-type-checking</code> is now an alias for <code>recommended-type-checked</code>.
The alias will be removed in a future major version.</p>
</blockquote>
<p>As of v6, we recommend that projects enable two configs from the above:</p>
<ul>
<li>If you are <em>not</em> using typed linting, enable <code>stylistic</code> and either <code>recommended</code> or <code>strict</code>, depending on how intensely you'd like your lint rules to scrutinize your code.</li>
<li>If you <em>are</em> using typed linting, enable <code>stylistic-type-checked</code> and either <code>recommended-type-checked</code> or <code>strict-type-checked</code>, depending on how intensely you'd like your lint rules to scrutinize your code.</li>
</ul>
<p>For example, a typical project that enables typed linting might have an ESLint configuration file that changes like:</p>
<div class="language-js codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockTitle_P25_">.eslintrc.cjs</div><div class="codeBlockContent_m3Ux"><pre class="prism-code language-js codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line"><span class="token plain">module</span><span class="token punctuation">.</span><span class="token property-access">exports</span><span class="token plain"> </span><span class="token operator">=</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token keyword">extends</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation">[</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">    </span><span class="token string">'eslint:recommended'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line code-block-removed-line"><span class="token plain">    </span><span class="token string">'plugin:@typescript-eslint/recommended'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line code-block-removed-line"><span class="token plain">    </span><span class="token string">'plugin:@typescript-eslint/recommended-requiring-type-checking'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line code-block-added-line"><span class="token plain">    </span><span class="token string">'plugin:@typescript-eslint/recommended-type-checked'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line code-block-added-line"><span class="token plain">    </span><span class="token string">'plugin:@typescript-eslint/stylistic-type-checked'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token punctuation">]</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token literal-property property">plugins</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation">[</span><span class="token string">'@typescript-eslint'</span><span class="token punctuation">]</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token literal-property property">parser</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'@typescript-eslint/parser'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token literal-property property">parserOptions</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line code-block-removed-line"><span class="token plain">    </span><span class="token literal-property property">project</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'./tsconfig.json'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line code-block-added-line"><span class="token plain">    </span><span class="token literal-property property">project</span><span class="token operator">:</span><span class="token plain"> </span><span class="token boolean">true</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">    </span><span class="token literal-property property">tsconfigRootDir</span><span class="token operator">:</span><span class="token plain"> __dirname</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token punctuation">}</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token literal-property property">root</span><span class="token operator">:</span><span class="token plain"> </span><span class="token boolean">true</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token punctuation">}</span><span class="token punctuation">;</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>See <a href="https://typescript-eslint.io/users/configs">our <em>Configurations</em> linting docs</a> for the updated documentation on configurations provided by typescript-eslint.</p>
<p>For more information on these changes, see:</p>
<ul>
<li><a href="https://typescript-eslint.io/users/configs">Our documentation on our configurations</a>.</li>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/discussions/6019" target="_blank" rel="noopener noreferrer">Configs: Have recommended/strict configs include lesser configs, and simplify type checked names</a> for the discussion leading up to these configuration changes.</li>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/pull/5251" target="_blank" rel="noopener noreferrer">feat(eslint-plugin): rework configs: recommended, strict, stylistic; -type-checked</a> for the pull request implementing the changes.</li>
</ul>
<h3 class="anchor anchorWithStickyNavbar_eAos" id="updated-configuration-rules">Updated Configuration Rules<a href="https://typescript-eslint.io/blog/announcing-typescript-eslint-v6#updated-configuration-rules" class="hash-link" aria-label="Direct link to Updated Configuration Rules" title="Direct link to Updated Configuration Rules">​</a></h3>
<p>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 <a href="https://github.com/typescript-eslint/typescript-eslint/discussions/6014" target="_blank" rel="noopener noreferrer">Changes to configurations for 6.0.0</a> and <a href="https://github.com/typescript-eslint/typescript-eslint/discussions/7130" target="_blank" rel="noopener noreferrer">Configs: Last round of "final" changes to configs for v6</a> for a full description of the changes.</p>
<div class="theme-admonition theme-admonition-tip admonition_pzuZ alert alert--success"><div class="admonitionHeading_uJho"><span class="admonitionIcon_vMH2"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>tip</div><div class="admonitionContent_gazR"><p>If your ESLint configuration contains many <code>rules</code> configurations, we suggest the following strategy to start anew:</p><ol>
<li>Remove all your rules configurations</li>
<li>Extend from the preset configs that make sense for you</li>
<li>Run ESLint on your project</li>
<li>In your ESLint configuration, turn off any rules creating errors that don't make sense for your project - with comments explaining why</li>
<li>In your ESLint configuration and/or with inline <code>eslint-disable</code> comments, turn off any rules creating too many errors for you to fix - with <em>"TODO"</em> comments linking to tracking issues/tickets to re-enable them</li>
</ol></div></div>
<p>Miscellaneous changes to all shared configurations include:</p>
<ul>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/pull/5381" target="_blank" rel="noopener noreferrer">fix(eslint-plugin): remove valid-typeof disable in eslint-recommended</a>: Removes the disabling of ESLint's <code>valid-typeof</code> rule from our preset configs.</li>
</ul>
<details class="details_JN11 alert alert--info details_tgxR" data-collapsed="true"><summary>Diff patch from v5's <em><code>recommended</code></em> to v6's <em><code>recommended</code></em> and <em><code>stylistic</code></em> configs</summary><div><div class="collapsibleContent_BLuU"><div class="language-diff codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockContent_m3Ux"><pre class="prism-code language-diff codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line"><span class="token plain">{</span><br></span><span class="token-line"><span class="token plain"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/adjacent-overload-signatures': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token inserted-sign inserted prefix inserted">+</span><span class="token inserted-sign inserted line">  '@typescript-eslint/array-type': '...',</span><br></span><span class="token-line"><span class="token inserted-sign inserted line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/ban-ts-comment': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token inserted-sign inserted prefix inserted">+</span><span class="token inserted-sign inserted line">  '@typescript-eslint/ban-tslint-comment': '...',</span><br></span><span class="token-line"><span class="token inserted-sign inserted line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/ban-types': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token inserted-sign inserted prefix inserted">+</span><span class="token inserted-sign inserted line">  '@typescript-eslint/class-literal-property-style': '...',</span><br></span><span class="token-line"><span class="token inserted-sign inserted line"></span><span class="token inserted-sign inserted prefix inserted">+</span><span class="token inserted-sign inserted line">  '@typescript-eslint/consistent-generic-constructors': '...',</span><br></span><span class="token-line"><span class="token inserted-sign inserted line"></span><span class="token inserted-sign inserted prefix inserted">+</span><span class="token inserted-sign inserted line">  '@typescript-eslint/consistent-indexed-object-style': '...',</span><br></span><span class="token-line"><span class="token inserted-sign inserted line"></span><span class="token inserted-sign inserted prefix inserted">+</span><span class="token inserted-sign inserted line">  '@typescript-eslint/consistent-type-assertions': '...',</span><br></span><span class="token-line"><span class="token inserted-sign inserted line"></span><span class="token inserted-sign inserted prefix inserted">+</span><span class="token inserted-sign inserted line">  '@typescript-eslint/consistent-type-definitions': '...',</span><br></span><span class="token-line"><span class="token inserted-sign inserted line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  'no-array-constructor': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-array-constructor': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token inserted-sign inserted prefix inserted">+</span><span class="token inserted-sign inserted line">  '@typescript-eslint/no-confusing-non-null-assertion': '...',</span><br></span><span class="token-line"><span class="token inserted-sign inserted line"></span><span class="token inserted-sign inserted prefix inserted">+</span><span class="token inserted-sign inserted line">  '@typescript-eslint/no-duplicate-enum-values': '...',</span><br></span><span class="token-line"><span class="token inserted-sign inserted line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  'no-empty-function': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-empty-function': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-empty-interface': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-explicit-any': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-extra-non-null-assertion': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token deleted-sign deleted prefix deleted">-</span><span class="token deleted-sign deleted line">  'no-extra-semi': '...',</span><br></span><span class="token-line"><span class="token deleted-sign deleted line"></span><span class="token deleted-sign deleted prefix deleted">-</span><span class="token deleted-sign deleted line">  '@typescript-eslint/no-extra-semi': '...',</span><br></span><span class="token-line"><span class="token deleted-sign deleted line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-inferrable-types': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  'no-loss-of-precision': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-loss-of-precision': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-misused-new': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-namespace': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-non-null-asserted-optional-chain': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token deleted-sign deleted prefix deleted">-</span><span class="token deleted-sign deleted line">  '@typescript-eslint/no-non-null-assertion': '...',</span><br></span><span class="token-line"><span class="token deleted-sign deleted line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-this-alias': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-unnecessary-type-constraint': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token inserted-sign inserted prefix inserted">+</span><span class="token inserted-sign inserted line">  '@typescript-eslint/no-unsafe-declaration-merging': '...',</span><br></span><span class="token-line"><span class="token inserted-sign inserted line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  'no-unused-vars': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-unused-vars': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-var-requires': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/prefer-as-const': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token inserted-sign inserted prefix inserted">+</span><span class="token inserted-sign inserted line">  '@typescript-eslint/prefer-for-of': '...',</span><br></span><span class="token-line"><span class="token inserted-sign inserted line"></span><span class="token inserted-sign inserted prefix inserted">+</span><span class="token inserted-sign inserted line">  '@typescript-eslint/prefer-function-type': '...',</span><br></span><span class="token-line"><span class="token inserted-sign inserted line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/prefer-namespace-keyword': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/triple-slash-reference': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token plain">}</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div></div></div></details>
<details class="details_JN11 alert alert--info details_tgxR" data-collapsed="true"><summary>Diff patch from v5's <em><code>recommended</code></em> and  <em><code>recommended-type-checked</code></em> to v6's <em><code>recommended-type-checked</code></em> and <em><code>stylistic-type-checked</code></em> configs</summary><div><div class="collapsibleContent_BLuU"><div class="language-diff codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockContent_m3Ux"><pre class="prism-code language-diff codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line"><span class="token plain">{</span><br></span><span class="token-line"><span class="token plain"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/adjacent-overload-signatures': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token inserted-sign inserted prefix inserted">+</span><span class="token inserted-sign inserted line">  '@typescript-eslint/array-type': '...',</span><br></span><span class="token-line"><span class="token inserted-sign inserted line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/await-thenable': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/ban-ts-comment': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token inserted-sign inserted prefix inserted">+</span><span class="token inserted-sign inserted line">  '@typescript-eslint/ban-tslint-comment': '...',</span><br></span><span class="token-line"><span class="token inserted-sign inserted line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/ban-types': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token inserted-sign inserted prefix inserted">+</span><span class="token inserted-sign inserted line">  '@typescript-eslint/class-literal-property-style': '...',</span><br></span><span class="token-line"><span class="token inserted-sign inserted line"></span><span class="token inserted-sign inserted prefix inserted">+</span><span class="token inserted-sign inserted line">  '@typescript-eslint/consistent-generic-constructors': '...',</span><br></span><span class="token-line"><span class="token inserted-sign inserted line"></span><span class="token inserted-sign inserted prefix inserted">+</span><span class="token inserted-sign inserted line">  '@typescript-eslint/consistent-indexed-object-style': '...',</span><br></span><span class="token-line"><span class="token inserted-sign inserted line"></span><span class="token inserted-sign inserted prefix inserted">+</span><span class="token inserted-sign inserted line">  '@typescript-eslint/consistent-type-assertions': '...',</span><br></span><span class="token-line"><span class="token inserted-sign inserted line"></span><span class="token inserted-sign inserted prefix inserted">+</span><span class="token inserted-sign inserted line">  '@typescript-eslint/consistent-type-definitions': '...',</span><br></span><span class="token-line"><span class="token inserted-sign inserted line"></span><span class="token inserted-sign inserted prefix inserted">+</span><span class="token inserted-sign inserted line">  'dot-notation': '...',</span><br></span><span class="token-line"><span class="token inserted-sign inserted line"></span><span class="token inserted-sign inserted prefix inserted">+</span><span class="token inserted-sign inserted line">  '@typescript-eslint/dot-notation': '...',</span><br></span><span class="token-line"><span class="token inserted-sign inserted line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  'no-array-constructor': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-array-constructor': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token inserted-sign inserted prefix inserted">+</span><span class="token inserted-sign inserted line">  '@typescript-eslint/no-base-to-string': '...',</span><br></span><span class="token-line"><span class="token inserted-sign inserted line"></span><span class="token inserted-sign inserted prefix inserted">+</span><span class="token inserted-sign inserted line">  '@typescript-eslint/no-confusing-non-null-assertion': '...',</span><br></span><span class="token-line"><span class="token inserted-sign inserted line"></span><span class="token inserted-sign inserted prefix inserted">+</span><span class="token inserted-sign inserted line">  '@typescript-eslint/no-duplicate-enum-values': '...',</span><br></span><span class="token-line"><span class="token inserted-sign inserted line"></span><span class="token inserted-sign inserted prefix inserted">+</span><span class="token inserted-sign inserted line">  '@typescript-eslint/no-duplicate-type-constituents': '...',</span><br></span><span class="token-line"><span class="token inserted-sign inserted line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  'no-empty-function': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-empty-function': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-empty-interface': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-explicit-any': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-extra-non-null-assertion': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token deleted-sign deleted prefix deleted">-</span><span class="token deleted-sign deleted line">  'no-extra-semi': '...',</span><br></span><span class="token-line"><span class="token deleted-sign deleted line"></span><span class="token deleted-sign deleted prefix deleted">-</span><span class="token deleted-sign deleted line">  '@typescript-eslint/no-extra-semi': '...',</span><br></span><span class="token-line"><span class="token deleted-sign deleted line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-floating-promises': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-for-in-array': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  'no-implied-eval': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-implied-eval': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-inferrable-types': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  'no-loss-of-precision': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-loss-of-precision': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-misused-new': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-misused-promises': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-namespace': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-non-null-asserted-optional-chain': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token deleted-sign deleted prefix deleted">-</span><span class="token deleted-sign deleted line">  '@typescript-eslint/no-non-null-assertion': '...',</span><br></span><span class="token-line"><span class="token deleted-sign deleted line"></span><span class="token inserted-sign inserted prefix inserted">+</span><span class="token inserted-sign inserted line">  '@typescript-eslint/no-redundant-type-constituents': '...',</span><br></span><span class="token-line"><span class="token inserted-sign inserted line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-this-alias': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-unnecessary-type-assertion': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-unnecessary-type-constraint': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-unsafe-argument': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-unsafe-assignment': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-unsafe-call': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token inserted-sign inserted prefix inserted">+</span><span class="token inserted-sign inserted line">  '@typescript-eslint/no-unsafe-declaration-merging': '...',</span><br></span><span class="token-line"><span class="token inserted-sign inserted line"></span><span class="token inserted-sign inserted prefix inserted">+</span><span class="token inserted-sign inserted line">  '@typescript-eslint/no-unsafe-enum-comparison': '...',</span><br></span><span class="token-line"><span class="token inserted-sign inserted line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-unsafe-member-access': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-unsafe-return': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  'no-unused-vars': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-unused-vars': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/no-var-requires': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token inserted-sign inserted prefix inserted">+</span><span class="token inserted-sign inserted line">  '@typescript-eslint/non-nullable-type-assertion-style': '...',</span><br></span><span class="token-line"><span class="token inserted-sign inserted line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/prefer-as-const': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token inserted-sign inserted prefix inserted">+</span><span class="token inserted-sign inserted line">  '@typescript-eslint/prefer-for-of': '...',</span><br></span><span class="token-line"><span class="token inserted-sign inserted line"></span><span class="token inserted-sign inserted prefix inserted">+</span><span class="token inserted-sign inserted line">  '@typescript-eslint/prefer-function-type': '...',</span><br></span><span class="token-line"><span class="token inserted-sign inserted line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/prefer-namespace-keyword': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token inserted-sign inserted prefix inserted">+</span><span class="token inserted-sign inserted line">  '@typescript-eslint/prefer-nullish-coalescing': '...',</span><br></span><span class="token-line"><span class="token inserted-sign inserted line"></span><span class="token inserted-sign inserted prefix inserted">+</span><span class="token inserted-sign inserted line">  '@typescript-eslint/prefer-optional-chain': '...',</span><br></span><span class="token-line"><span class="token inserted-sign inserted line"></span><span class="token inserted-sign inserted prefix inserted">+</span><span class="token inserted-sign inserted line">  '@typescript-eslint/prefer-string-starts-ends-with': '...',</span><br></span><span class="token-line"><span class="token inserted-sign inserted line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  'require-await': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/require-await': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/restrict-plus-operands': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/restrict-template-expressions': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/triple-slash-reference': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token unchanged prefix unchanged"> </span><span class="token unchanged line">  '@typescript-eslint/unbound-method': '...',</span><br></span><span class="token-line"><span class="token unchanged line"></span><span class="token plain">}</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div></div></div></details>
<details class="details_JN11 alert alert--info details_tgxR" data-collapsed="true"><summary>Code that generated those diffs</summary><div><div class="collapsibleContent_BLuU"><div class="language-js codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockContent_m3Ux"><pre class="prism-code language-js codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line"><span class="token keyword">const</span><span class="token plain"> v5Recommended </span><span class="token operator">=</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/adjacent-overload-signatures'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/ban-ts-comment'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/ban-types'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'no-array-constructor'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'off'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/no-array-constructor'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'no-empty-function'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'off'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/no-empty-function'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/no-empty-interface'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/no-explicit-any'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'warn'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/no-extra-non-null-assertion'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'no-extra-semi'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'off'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/no-extra-semi'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/no-inferrable-types'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'no-loss-of-precision'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'off'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/no-loss-of-precision'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/no-misused-new'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/no-namespace'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/no-non-null-asserted-optional-chain'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/no-non-null-assertion'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'warn'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/no-this-alias'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/no-unnecessary-type-constraint'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'no-unused-vars'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'off'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/no-unused-vars'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'warn'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/no-var-requires'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/prefer-as-const'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/prefer-namespace-keyword'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/triple-slash-reference'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token punctuation">}</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token keyword">const</span><span class="token plain"> v5RecommendedRequiringTypeChecking </span><span class="token operator">=</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/await-thenable'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/no-floating-promises'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/no-for-in-array'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'no-implied-eval'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'off'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/no-implied-eval'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/no-misused-promises'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/no-unnecessary-type-assertion'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/no-unsafe-argument'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/no-unsafe-assignment'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/no-unsafe-call'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/no-unsafe-member-access'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/no-unsafe-return'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'require-await'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'off'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/require-await'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/restrict-plus-operands'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/restrict-template-expressions'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/unbound-method'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token punctuation">}</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token keyword">const</span><span class="token plain"> v6Recommended </span><span class="token operator">=</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/ban-ts-comment'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/ban-types'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'no-array-constructor'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'off'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/no-array-constructor'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/no-duplicate-enum-values'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/no-explicit-any'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/no-extra-non-null-assertion'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'no-loss-of-precision'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'off'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/no-loss-of-precision'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/no-misused-new'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/no-namespace'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/no-non-null-asserted-optional-chain'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/no-this-alias'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/no-unnecessary-type-constraint'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/no-unsafe-declaration-merging'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'no-unused-vars'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'off'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/no-unused-vars'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/no-var-requires'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/prefer-as-const'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/triple-slash-reference'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token punctuation">}</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token keyword">const</span><span class="token plain"> v6RecommendedTypeChecked </span><span class="token operator">=</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/await-thenable'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/ban-ts-comment'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/ban-types'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'no-array-constructor'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'off'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/no-array-constructor'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/no-base-to-string'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/no-duplicate-enum-values'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/no-duplicate-type-constituents'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/no-explicit-any'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/no-extra-non-null-assertion'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/no-floating-promises'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/no-for-in-array'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'no-implied-eval'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'off'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/no-implied-eval'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'no-loss-of-precision'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'off'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/no-loss-of-precision'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/no-misused-new'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/no-misused-promises'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/no-namespace'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/no-non-null-asserted-optional-chain'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/no-redundant-type-constituents'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/no-this-alias'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/no-unnecessary-type-assertion'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/no-unnecessary-type-constraint'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/no-unsafe-argument'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/no-unsafe-assignment'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/no-unsafe-call'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/no-unsafe-declaration-merging'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/no-unsafe-enum-comparison'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/no-unsafe-member-access'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/no-unsafe-return'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'no-unused-vars'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'off'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/no-unused-vars'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/no-var-requires'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/prefer-as-const'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'require-await'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'off'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/require-await'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/restrict-plus-operands'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/restrict-template-expressions'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/triple-slash-reference'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/unbound-method'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token punctuation">}</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token keyword">const</span><span class="token plain"> v6Stylistic </span><span class="token operator">=</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/adjacent-overload-signatures'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/array-type'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/ban-tslint-comment'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/class-literal-property-style'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/consistent-generic-constructors'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/consistent-indexed-object-style'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/consistent-type-assertions'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/consistent-type-definitions'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/no-confusing-non-null-assertion'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'no-empty-function'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'off'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/no-empty-function'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/no-empty-interface'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/no-inferrable-types'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/prefer-for-of'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/prefer-function-type'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/prefer-namespace-keyword'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token punctuation">}</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token keyword">const</span><span class="token plain"> v6StylisticTypeChecked </span><span class="token operator">=</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/adjacent-overload-signatures'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/array-type'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/ban-tslint-comment'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/class-literal-property-style'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/consistent-generic-constructors'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/consistent-indexed-object-style'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/consistent-type-assertions'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/consistent-type-definitions'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'dot-notation'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'off'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/dot-notation'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/no-confusing-non-null-assertion'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'no-empty-function'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'off'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/no-empty-function'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/no-empty-interface'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/no-inferrable-types'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/non-nullable-type-assertion-style'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/prefer-for-of'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/prefer-function-type'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/prefer-namespace-keyword'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/prefer-nullish-coalescing'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/prefer-optional-chain'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string-property property">'@typescript-eslint/prefer-string-starts-ends-with'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token punctuation">}</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token keyword">function</span><span class="token plain"> </span><span class="token function">createDiffPatch</span><span class="token punctuation">(</span><span class="token parameter">v5</span><span class="token parameter punctuation">,</span><span class="token parameter"> v6</span><span class="token punctuation">)</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token keyword">const</span><span class="token plain"> v5Keys </span><span class="token operator">=</span><span class="token plain"> </span><span class="token keyword">new</span><span class="token plain"> </span><span class="token class-name">Set</span><span class="token punctuation">(</span><span class="token known-class-name class-name">Object</span><span class="token punctuation">.</span><span class="token method function property-access">keys</span><span class="token punctuation">(</span><span class="token plain">v5</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token keyword">const</span><span class="token plain"> v6Keys </span><span class="token operator">=</span><span class="token plain"> </span><span class="token keyword">new</span><span class="token plain"> </span><span class="token class-name">Set</span><span class="token punctuation">(</span><span class="token known-class-name class-name">Object</span><span class="token punctuation">.</span><span class="token method function property-access">keys</span><span class="token punctuation">(</span><span class="token plain">v6</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token keyword">const</span><span class="token plain"> output </span><span class="token operator">=</span><span class="token plain"> </span><span class="token punctuation">[</span><span class="token string">'{'</span><span class="token punctuation">]</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token keyword control-flow">for</span><span class="token plain"> </span><span class="token punctuation">(</span><span class="token keyword">const</span><span class="token plain"> key </span><span class="token keyword">of</span><span class="token plain"> </span><span class="token known-class-name class-name">Array</span><span class="token punctuation">.</span><span class="token keyword module">from</span><span class="token punctuation">(</span><span class="token keyword">new</span><span class="token plain"> </span><span class="token class-name">Set</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token spread operator">...</span><span class="token plain">v5Keys</span><span class="token punctuation">,</span><span class="token plain"> </span><span class="token spread operator">...</span><span class="token plain">v6Keys</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token method function property-access">sort</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">a</span><span class="token parameter punctuation">,</span><span class="token parameter"> b</span><span class="token punctuation">)</span><span class="token plain"> </span><span class="token arrow operator">=&gt;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">    </span><span class="token function">trimSlash</span><span class="token punctuation">(</span><span class="token plain">a</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token method function property-access">localeCompare</span><span class="token punctuation">(</span><span class="token function">trimSlash</span><span class="token punctuation">(</span><span class="token plain">b</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">    </span><span class="token keyword">const</span><span class="token plain"> prefix </span><span class="token operator">=</span><span class="token plain"> v5Keys</span><span class="token punctuation">.</span><span class="token method function property-access">has</span><span class="token punctuation">(</span><span class="token plain">key</span><span class="token punctuation">)</span><span class="token plain"> </span><span class="token operator">?</span><span class="token plain"> </span><span class="token punctuation">(</span><span class="token plain">v6Keys</span><span class="token punctuation">.</span><span class="token method function property-access">has</span><span class="token punctuation">(</span><span class="token plain">key</span><span class="token punctuation">)</span><span class="token plain"> </span><span class="token operator">?</span><span class="token plain"> </span><span class="token string">' '</span><span class="token plain"> </span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'-'</span><span class="token punctuation">)</span><span class="token plain"> </span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'+'</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line"><span class="token plain">    output</span><span class="token punctuation">.</span><span class="token method function property-access">push</span><span class="token punctuation">(</span><span class="token template-string template-punctuation string">`</span><span class="token template-string interpolation interpolation-punctuation punctuation">${</span><span class="token template-string interpolation">prefix</span><span class="token template-string interpolation interpolation-punctuation punctuation">}</span><span class="token template-string string">  '</span><span class="token template-string interpolation interpolation-punctuation punctuation">${</span><span class="token template-string interpolation">key</span><span class="token template-string interpolation interpolation-punctuation punctuation">}</span><span class="token template-string string">': '...',</span><span class="token template-string template-punctuation string">`</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token punctuation">}</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line"><span class="token plain">  output</span><span class="token punctuation">.</span><span class="token method function property-access">push</span><span class="token punctuation">(</span><span class="token string">'}'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token keyword control-flow">return</span><span class="token plain"> output</span><span class="token punctuation">.</span><span class="token method function property-access">join</span><span class="token punctuation">(</span><span class="token string">'\n'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token punctuation">}</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token keyword">function</span><span class="token plain"> </span><span class="token function">trimSlash</span><span class="token punctuation">(</span><span class="token parameter">text</span><span class="token punctuation">)</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token keyword control-flow">return</span><span class="token plain"> text</span><span class="token punctuation">.</span><span class="token method function property-access">startsWith</span><span class="token punctuation">(</span><span class="token string">'@typescript-eslint/'</span><span class="token punctuation">)</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">    </span><span class="token operator">?</span><span class="token plain"> text</span><span class="token punctuation">.</span><span class="token method function property-access">slice</span><span class="token punctuation">(</span><span class="token string">'@typescript-eslint/'</span><span class="token punctuation">.</span><span class="token property-access">length</span><span class="token punctuation">)</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">    </span><span class="token operator">:</span><span class="token plain"> text</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token punctuation">}</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token console class-name">console</span><span class="token punctuation">.</span><span class="token method function property-access">log</span><span class="token punctuation">(</span><span class="token string">'From v5 recommended to v6 recommended &amp; stylistic:'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token console class-name">console</span><span class="token punctuation">.</span><span class="token method function property-access">log</span><span class="token punctuation">(</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token function">createDiffPatch</span><span class="token punctuation">(</span><span class="token plain">v5Recommended</span><span class="token punctuation">,</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"> </span><span class="token spread operator">...</span><span class="token plain">v6Recommended</span><span class="token punctuation">,</span><span class="token plain"> </span><span class="token spread operator">...</span><span class="token plain">v6Stylistic </span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token console class-name">console</span><span class="token punctuation">.</span><span class="token method function property-access">log</span><span class="token punctuation">(</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token string">'\nFrom v5 recommended &amp; recommended-requiring-type-checking to v6 recommended-type-checked &amp; stylistic-type-checked:'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token console class-name">console</span><span class="token punctuation">.</span><span class="token method function property-access">log</span><span class="token punctuation">(</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token function">createDiffPatch</span><span class="token punctuation">(</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">    </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">      </span><span class="token spread operator">...</span><span class="token plain">v5Recommended</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">      </span><span class="token spread operator">...</span><span class="token plain">v5RecommendedRequiringTypeChecking</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">    </span><span class="token punctuation">}</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">    </span><span class="token punctuation">{</span><span class="token plain"> </span><span class="token spread operator">...</span><span class="token plain">v6RecommendedTypeChecked</span><span class="token punctuation">,</span><span class="token plain"> </span><span class="token spread operator">...</span><span class="token plain">v6StylisticTypeChecked </span><span class="token punctuation">}</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token punctuation">)</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token punctuation">)</span><span class="token punctuation">;</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div></div></div></details>
<h3 class="anchor anchorWithStickyNavbar_eAos" id="rule-breaking-changes">Rule Breaking Changes<a href="https://typescript-eslint.io/blog/announcing-typescript-eslint-v6#rule-breaking-changes" class="hash-link" aria-label="Direct link to Rule Breaking Changes" title="Direct link to Rule Breaking Changes">​</a></h3>
<p>Several rules were changed in significant enough ways to be considered breaking changes:</p>
<ul>
<li>Previously deprecated rules are deleted (<a href="https://github.com/typescript-eslint/typescript-eslint/pull/6112" target="_blank" rel="noopener noreferrer">chore(eslint-plugin): remove deprecated rules for v6</a>):<!-- -->
<ul>
<li><code>@typescript-eslint/no-duplicate-imports</code>, replaced by <code>imports/no-duplicates</code></li>
<li><code>@typescript-eslint/no-implicit-any-catch</code>, replaced by the TSConfig option <a href="https://www.typescriptlang.org/tsconfig#useUnknownInCatchVariables" target="_blank" rel="noopener noreferrer"><code>useUnknownInCatchVariables</code></a></li>
<li><code>@typescript-eslint/no-parameter-properties</code>, replaced by <code>@typescript-eslint/parameter-properties</code></li>
<li><code>@typescript-eslint/sort-type-union-intersection-members</code>, replaced by <code>@typescript-eslint/sort-type-constituents</code></li>
</ul>
</li>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/pull/5234" target="_blank" rel="noopener noreferrer">feat(eslint-plugin): [prefer-nullish-coalescing]: add support for assignment expressions</a>: Enhances the <a href="https://typescript-eslint.io/rules/prefer-nullish-coalescing"><code>@typescript-eslint/prefer-nullish-coalescing</code></a> rule to also check <code>||=</code> expressions.</li>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/pull/6240" target="_blank" rel="noopener noreferrer">feat(eslint-plugin): [prefer-optional-chain] use type checking for strict falsiness</a>: Fixes edge case bugs in the <a href="https://typescript-eslint.io/rules/prefer-optional-chain"><code>@typescript-eslint/prefer-optional-chain</code></a> rule around false positives, at the cost of making it require type information.</li>
<li>✨ <a href="https://github.com/typescript-eslint/typescript-eslint/pull/7027" target="_blank" rel="noopener noreferrer">feat(eslint-plugin): [restrict-plus-operands] change checkCompoundAssignments to skipCompoundAssignments</a>: inverses the logical value of the option and renames it</li>
<li>✨ <a href="https://github.com/typescript-eslint/typescript-eslint/pull/6397" target="_blank" rel="noopener noreferrer">feat(eslint-plugin): [prefer-optional-chain] handle cases where the first operands are unrelated to the rest of the chain and add type info</a>: uses type information to make the rule more intelligent about when to flag violations</li>
</ul>
<h3 class="anchor anchorWithStickyNavbar_eAos" id="tooling-breaking-changes">Tooling Breaking Changes<a href="https://typescript-eslint.io/blog/announcing-typescript-eslint-v6#tooling-breaking-changes" class="hash-link" aria-label="Direct link to Tooling Breaking Changes" title="Direct link to Tooling Breaking Changes">​</a></h3>
<ul>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/pull/5890" target="_blank" rel="noopener noreferrer">feat(typescript-estree): deprecate createDefaultProgram</a>: Renames <code>createDefaultProgram</code> to <code>deprecated__createDefaultProgram</code>, with associated <code>@deprecated</code> TSDoc tags and warnings.</li>
<li>Drop support for Node v12 and v14<!-- -->
<ul>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/pull/5918" target="_blank" rel="noopener noreferrer">feat: drop support for node v12</a></li>
<li>✨ <a href="https://github.com/typescript-eslint/typescript-eslint/pull/7022" target="_blank" rel="noopener noreferrer">feat: drop support for node v14 and test against node v20</a>: as Node 14 is now EOL</li>
</ul>
</li>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/pull/5915" target="_blank" rel="noopener noreferrer">feat: bump minimum supported TS version to 4.2.4</a>: this matches <a href="https://github.com/DefinitelyTyped/DefinitelyTyped#support-window" target="_blank" rel="noopener noreferrer">DefinitelyTyped's 2-year support window</a>.</li>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/pull/5972" target="_blank" rel="noopener noreferrer">chore: drop support for ESLint v6</a></li>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/pull/4436" target="_blank" rel="noopener noreferrer">feat(eslint-plugin): [prefer-readonly-parameter-types] added an optional type allowlist</a>: changes the public <code>isTypeReadonlyArrayOrTuple</code> function's first argument from a <code>checker: ts.TypeChecker</code> to a full <code>program: ts.Program</code></li>
<li>✨ <a href="https://github.com/typescript-eslint/typescript-eslint/pull/6777" target="_blank" rel="noopener noreferrer">feat: add new package <code>rule-tester</code></a>: creates a new <code>@typescript-eslint/rule-tester</code> package for testing rules, and updates our documentation to recommend it</li>
</ul>
<h2 class="anchor anchorWithStickyNavbar_eAos" id="developer-facing-changes">Developer-Facing Changes<a href="https://typescript-eslint.io/blog/announcing-typescript-eslint-v6#developer-facing-changes" class="hash-link" aria-label="Direct link to Developer-Facing Changes" title="Direct link to Developer-Facing Changes">​</a></h2>
<p>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.</p>
<div class="theme-admonition theme-admonition-tip admonition_pzuZ alert alert--success"><div class="admonitionHeading_uJho"><span class="admonitionIcon_vMH2"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>tip</div><div class="admonitionContent_gazR"><p>If you're having trouble with the changes, please let us know on <a href="https://discord.gg/FSxKq8Tdyg" target="_blank" rel="noopener noreferrer">the typescript-eslint Discord</a>!</p></div></div>
<h3 class="anchor anchorWithStickyNavbar_eAos" id="type-checker-wrapper-apis">Type Checker Wrapper APIs<a href="https://typescript-eslint.io/blog/announcing-typescript-eslint-v6#type-checker-wrapper-apis" class="hash-link" aria-label="Direct link to Type Checker Wrapper APIs" title="Direct link to Type Checker Wrapper APIs">​</a></h3>
<p>As described in our <a href="https://typescript-eslint.io/blog/asts-and-typescript-eslint">ASTs and typescript-eslint</a> 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:</p>
<div class="language-ts codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockTitle_P25_">custom-rule-with-v5.ts</div><div class="codeBlockContent_m3Ux"><pre class="prism-code language-ts codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line"><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token comment">// ...</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token function">create</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">    </span><span class="token keyword">const</span><span class="token plain"> services </span><span class="token operator">=</span><span class="token plain"> util</span><span class="token punctuation">.</span><span class="token function">getParserServices</span><span class="token punctuation">(</span><span class="token plain">context</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">    </span><span class="token keyword">const</span><span class="token plain"> checker </span><span class="token operator">=</span><span class="token plain"> services</span><span class="token punctuation">.</span><span class="token plain">program</span><span class="token punctuation">.</span><span class="token function">getTypeChecker</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">    </span><span class="token keyword">const</span><span class="token plain"> tsNode </span><span class="token operator">=</span><span class="token plain"> services</span><span class="token punctuation">.</span><span class="token plain">esTreeNodeToTSNodeMap</span><span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token plain">esNode</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">    </span><span class="token keyword">const</span><span class="token plain"> type </span><span class="token operator">=</span><span class="token plain"> checker</span><span class="token punctuation">.</span><span class="token function">getTypeAtLocation</span><span class="token punctuation">(</span><span class="token plain">node</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line"><span class="token plain">    </span><span class="token comment">// ...</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token punctuation">}</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token comment">// ...</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token punctuation">}</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>How cumbersome, just to call to a single method (<code>getTypeAtLocation</code>) on the TypeScript API!</p>
<p>In typescript-eslint v6, we've added a set of wrapper APIs on the <code>services: ParserServices</code> object that act as shortcuts for commonly used TypeScript APIs including <code>getTypeAtLocation</code>:</p>
<div class="language-ts codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockTitle_P25_">custom-rule-with-v6.ts</div><div class="codeBlockContent_m3Ux"><pre class="prism-code language-ts codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line"><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token comment">// ...</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token function">create</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">    </span><span class="token keyword">const</span><span class="token plain"> services </span><span class="token operator">=</span><span class="token plain"> util</span><span class="token punctuation">.</span><span class="token function">getParserServices</span><span class="token punctuation">(</span><span class="token plain">context</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">    </span><span class="token keyword">const</span><span class="token plain"> type </span><span class="token operator">=</span><span class="token plain"> services</span><span class="token punctuation">.</span><span class="token function">getTypeAtLocation</span><span class="token punctuation">(</span><span class="token plain">node</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line"><span class="token plain">    </span><span class="token comment">// ...</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token punctuation">}</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token comment">// ...</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token punctuation">}</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>For now, the available wrapper APIs are:</p>
<ul>
<li><code>getSymbolAtLocation</code>: passes an ESTree's equivalent TypeScript node to <code>checker.getSymbolAtLocation</code></li>
<li><code>getTypeAtLocation</code>: passes an ESTree node's equivalent TypeScript node to <code>checker.getTypeAtLocation</code></li>
</ul>
<p>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.</p>
<div class="theme-admonition theme-admonition-note admonition_pzuZ alert alert--secondary"><div class="admonitionHeading_uJho"><span class="admonitionIcon_vMH2"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>note</div><div class="admonitionContent_gazR"><p>Rules can still retrieve their full backing TypeScript type checker with <code>services.program.getTypeChecker()</code>.
This can be necessary for TypeScript APIs not wrapped by the parser services.</p></div></div>
<p>See <a href="https://typescript-eslint.io/developers/custom-rules"><em>Custom Rules</em></a> for the updated documentation on creating custom rules with typescript-eslint.</p>
<h3 class="anchor anchorWithStickyNavbar_eAos" id="ast-breaking-changes">AST Breaking Changes<a href="https://typescript-eslint.io/blog/announcing-typescript-eslint-v6#ast-breaking-changes" class="hash-link" aria-label="Direct link to AST Breaking Changes" title="Direct link to AST Breaking Changes">​</a></h3>
<p>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.</p>
<ul>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/pull/4863" target="_blank" rel="noopener noreferrer">feat: remove semantically invalid properties from TSEnumDeclaration, TSInterfaceDeclaration and TSModuleDeclaration</a>: Removes some properties from those AST node types that should generally not have existed to begin with.</li>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/pull/5036" target="_blank" rel="noopener noreferrer">fix(utils): removed TRuleListener generic from the createRule</a>: Makes <code>createRule</code>-created rules more portable in the type system.</li>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/pull/5252" target="_blank" rel="noopener noreferrer">feat: made BaseNode.parent non-optional</a>: makes the <code>node.parent</code> property on AST nodes non-optional (<code>TSESTree.Node</code> instead of <code>TSESTree.Node | undefined</code>).</li>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/pull/5384" target="_blank" rel="noopener noreferrer">fix: rename typeParameters to typeArguments where needed</a>: corrects the names of AST properties that were called <em>parameters</em> instead of <em>arguments</em>.<!-- -->
<ul>
<li>To recap the terminology:<!-- -->
<ul>
<li>An <em>argument</em> is something you provide to a recipient, such as a type provided explicitly to a call expression.</li>
<li>A <em>parameter</em> is how the recipient receives what you provide, such as a function declaration's generic type parameter.</li>
</ul>
</li>
</ul>
</li>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/pull/6257" target="_blank" rel="noopener noreferrer">fix(ast-spec): correct some incorrect ast types</a>: applies the following changes to correct erroneous types of AST node properties:<!-- -->
<ul>
<li><code>ArrayExpressions</code>'s <code>elements</code> property can now include <code>null</code> (i.e. is now <code>(Expression | SpreadElement | null)[]</code>), for the case of sparse arrays (e.g. <code>[1, , 3]</code>).</li>
<li><code>MemberExpression</code>'s <code>object</code> property is now <code>Expression</code>, not <code>LeftHandSideExpression</code>.</li>
<li><code>ObjectLiteralElement</code> no longer allows for <code>MethodDefinition</code>.</li>
</ul>
</li>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/pull/5885" target="_blank" rel="noopener noreferrer">fix(typescript-estree): wrap import = declaration in an export node</a>: Exported <code>TSImportEqualsDeclaration</code> nodes are now wrapped in an <code>ExportNamedDeclaration</code> node instead of having <code>.isExport = true</code> property.</li>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/pull/6243" target="_blank" rel="noopener noreferrer">fix(ast-spec): remove more invalid properties</a>: applies the following changes to remove invalid properties from AST nodes:<!-- -->
<ul>
<li><code>MethodDefinitionBase</code> no longer has a <code>typeParameters</code> property.</li>
<li><code>TSIndexSignature</code>, <code>TSMethodSignature</code>, and <code>TSPropertySignatureBase</code> no longer have an <code>export</code> property.</li>
<li><code>TSPropertySignatureBase</code> no longer has an <code>initializer</code> property.</li>
</ul>
</li>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/pull/6272" target="_blank" rel="noopener noreferrer">fix(typescript-estree): account for namespace nesting in AST conversion</a>: Namespaces with qualified names like <code>Abc.Def</code> now use a <code>TSQualifiedName</code> node, instead of a nested body structure.</li>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/pull/6274" target="_blank" rel="noopener noreferrer">feat(typescript-estree): remove optionality from AST boolean properties</a>: Switches most AST properties marked as <code>?: boolean</code> to <code>: boolean</code>, as well as some properties marked as <code>?:</code> optional to <code>| undefined</code>. This results in more predictable AST node object shapes.</li>
</ul>
<h3 class="anchor anchorWithStickyNavbar_eAos" id="errors-on-invalid-ast-parsing">Errors on Invalid AST Parsing<a href="https://typescript-eslint.io/blog/announcing-typescript-eslint-v6#errors-on-invalid-ast-parsing" class="hash-link" aria-label="Direct link to Errors on Invalid AST Parsing" title="Direct link to Errors on Invalid AST Parsing">​</a></h3>
<div class="theme-admonition theme-admonition-note admonition_pzuZ alert alert--secondary"><div class="admonitionHeading_uJho"><span class="admonitionIcon_vMH2"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>note</div><div class="admonitionContent_gazR"><p>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.</p></div></div>
<p>The <code>@typescript-eslint/typescript-estree</code> 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.</p>
<p>For example, this snippet of TypeScript code creates a <code>ClassDeclaration</code> whose <code>id</code> is <code>null</code>:</p>
<div class="language-ts codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockContent_m3Ux"><pre class="prism-code language-ts codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line"><span class="token keyword">export</span><span class="token plain"> </span><span class="token keyword">class</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token punctuation">}</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>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.</p>
<p><code>@typescript-eslint/typescript-estree</code> will now throw an error when it encounters a known invalid AST such as the <code>export class {}</code> example.
This is generally the correct behavior for most parsing contexts so downstream tools don't have to work with a potentially invalid AST.</p>
<p>For consumers that don't want the updated behavior of throwing on invalid ASTs, a new <code>allowInvalidAST</code> 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.</p>
<p>For more information, see:</p>
<ul>
<li>The backing issue: <a href="https://github.com/typescript-eslint/typescript-eslint/issues/1852" target="_blank" rel="noopener noreferrer">Parsing: strictly enforce the produced AST matches the spec and enforce most "error recovery" parsing errors</a></li>
<li>The implementing pull request: <a href="https://github.com/typescript-eslint/typescript-eslint/pull/6247" target="_blank" rel="noopener noreferrer">feat(typescript-estree): added allowInvalidAST option to throw on invalid tokens</a></li>
<li>✨ <a href="https://github.com/typescript-eslint/typescript-eslint/pull/6723" target="_blank" rel="noopener noreferrer">fix: fix illegal decorator check</a>: improves how invalid decorator syntax is parsed and reported on</li>
</ul>
<h3 class="anchor anchorWithStickyNavbar_eAos" id="package-exports">Package Exports<a href="https://typescript-eslint.io/blog/announcing-typescript-eslint-v6#package-exports" class="hash-link" aria-label="Direct link to Package Exports" title="Direct link to Package Exports">​</a></h3>
<p>The v5 <code>@typescript-eslint/*</code> packages don't use <a href="https://nodejs.org/api/packages.html#package-entry-points" target="_blank" rel="noopener noreferrer">Node.js package.json exports</a>, which allows importing any file in any package by directly referencing a path within the package's <code>dist/</code> directory.
For example:</p>
<div class="language-ts codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockContent_m3Ux"><pre class="prism-code language-ts codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line"><span class="token keyword">import</span><span class="token plain"> </span><span class="token operator">*</span><span class="token plain"> </span><span class="token keyword">as</span><span class="token plain"> TSESLint </span><span class="token keyword">from</span><span class="token plain"> </span><span class="token string">'@typescript-eslint/utils/dist/ts-eslint'</span><span class="token punctuation">;</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>That presents a few issues for developers:</p>
<ul>
<li>It can be unclear which of many potential import paths to use.</li>
<li>TypeScript sometimes suggests importing types or values meant to be private.</li>
<li>Consumers using deep import paths can be broken by internal refactors that rename files.</li>
</ul>
<p>As of <a href="https://github.com/typescript-eslint/typescript-eslint/pull/6458" target="_blank" rel="noopener noreferrer">feat: add package.json exports for public packages</a>, <code>@typescript-eslint/*</code> packages now use <code>exports</code> to prevent importing internal file paths.
Developers must now import directly from the package names, e.g.:</p>
<div class="language-ts codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockContent_m3Ux"><pre class="prism-code language-ts codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line"><span class="token comment">// import * as TSESLint from '@typescript-eslint/utils/dist/ts-eslint';</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token comment">// --&gt;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token keyword">import</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"> TSESLint </span><span class="token punctuation">}</span><span class="token plain"> </span><span class="token keyword">from</span><span class="token plain"> </span><span class="token string">'@typescript-eslint/utils'</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token comment">// The following would also work and be equivalent:</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token comment">// import * as TSESLint from '@typescript-eslint/utils/ts-eslint';</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token comment">// But explicit importing should be generally favored over star imports.</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token comment">// import { RuleModule } from '@typescript-eslint/utils/dist/ts-eslint';</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token comment">// --&gt;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token keyword">import</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"> RuleModule </span><span class="token punctuation">}</span><span class="token plain"> </span><span class="token keyword">from</span><span class="token plain"> </span><span class="token string">'@typescript-eslint/utils/ts-eslint'</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token comment">// import { AST_NODE_TYPES } from "@typescript-eslint/types/dist/generated/ast-spec";</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token comment">// --&gt;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token keyword">import</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"> </span><span class="token constant">AST_NODE_TYPES</span><span class="token plain"> </span><span class="token punctuation">}</span><span class="token plain"> </span><span class="token keyword">from</span><span class="token plain"> </span><span class="token string">'@typescript-eslint/types'</span><span class="token punctuation">;</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>See <a href="https://github.com/typescript-eslint/typescript-eslint/discussions/6015" target="_blank" rel="noopener noreferrer">RFC: Use package.json exports to "hide" the dist folder for packages and control our exported surface-area</a> for more backing context.</p>
<div class="theme-admonition theme-admonition-note admonition_pzuZ alert alert--secondary"><div class="admonitionHeading_uJho"><span class="admonitionIcon_vMH2"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>note</div><div class="admonitionContent_gazR"><p>If you update your imports and you still get an error from TypeScript saying <em><code>"Cannot find module '@typescript-eslint/...' or its corresponding type declarations"</code></em>, then you might need to change the value of <code>moduleResolution</code> in your TypeScript config. See <a href="https://github.com/typescript-eslint/typescript-eslint/issues/7284" target="_blank" rel="noopener noreferrer">this tracking issue for <code>package.json</code> exports types</a>.</p></div></div>
<h3 class="anchor anchorWithStickyNavbar_eAos" id="other-developer-facing-breaking-changes">Other Developer-Facing Breaking Changes<a href="https://typescript-eslint.io/blog/announcing-typescript-eslint-v6#other-developer-facing-breaking-changes" class="hash-link" aria-label="Direct link to Other Developer-Facing Breaking Changes" title="Direct link to Other Developer-Facing Breaking Changes">​</a></h3>
<ul>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/pull/5256" target="_blank" rel="noopener noreferrer">feat(utils): remove (ts-)eslint-scope types</a>: Removes no-longer-useful <code>TSESLintScope</code> types from the <code>@typescript-eslint/utils</code> package. Use <code>@typescript-eslint/scope-manager</code> directly instead.</li>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/issues/6469" target="_blank" rel="noopener noreferrer">Enhancement: Add test-only console warnings to deprecated AST properties</a>: The properties will include a <code>console.log</code> that triggers only in test environments, to encourage developers to move off of them.</li>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/pull/5889" target="_blank" rel="noopener noreferrer">feat(scope-manager): ignore ECMA version</a>: <code>@typescript-eslint/scope-manager</code> no longer includes properties referring to <code>ecmaVersion</code>, <code>isES6</code>, or other ECMA versioning options. It instead now always assumes ESNext.</li>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/pull/6066" target="_blank" rel="noopener noreferrer">feat: remove partial type-information program</a>: When user configurations don't provide a <code>parserOptions.project</code>, parser services will no longer include a <code>program</code> with incomplete type information. <code>program</code> will be <code>null</code> instead.</li>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/pull/6468" target="_blank" rel="noopener noreferrer">feat: remove experimental-utils</a>: The <code>@typescript-eslint/experimental-utils</code> package has since been renamed to <code>@typescript-eslint/utils</code>.<!-- -->
<ul>
<li>As a result, the <code>errorOnTypeScriptSyntacticAndSemanticIssues</code> option will no longer be allowed if <code>parserOptions.project</code> is not provided.</li>
</ul>
</li>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/pull/6242" target="_blank" rel="noopener noreferrer">chore(typescript-estree): remove visitor-keys backwards compat export</a>: <code>visitorKeys</code> can now only be imported from <code>@typescript-eslint/visitor-keys</code>. Previously it was also re-exported by <code>@typescript-eslint/utils</code>.</li>
<li>✨ <a href="https://github.com/typescript-eslint/typescript-eslint/pull/6963" target="_blank" rel="noopener noreferrer">feat: fork json schema types for better compat with ESLint rule validation</a>: clarifies the JSON schema types exported for rule options to match ESLint's and remove an unsafe <code>[string: any]</code> index</li>
<li>✨ <a href="https://github.com/typescript-eslint/typescript-eslint/pull/7120" target="_blank" rel="noopener noreferrer">feat(typescript-estree): remove parseWithNodeMaps</a>: removed a <code>parseWithNodeMaps</code> API previously intended only for Prettier that is no longer used by Prettier</li>
<li>✨ <a href="https://github.com/typescript-eslint/typescript-eslint/issues/7124" target="_blank" rel="noopener noreferrer">Consider keeping parserServices.hasFullTypeInformation for another major version?</a>: we're removing an old, undocumented <code>hasFullTypeInformation</code> property from <code>parserServices</code>.</li>
</ul>
<h2 class="anchor anchorWithStickyNavbar_eAos" id="appreciation">Appreciation<a href="https://typescript-eslint.io/blog/announcing-typescript-eslint-v6#appreciation" class="hash-link" aria-label="Direct link to Appreciation" title="Direct link to Appreciation">​</a></h2>
<p>We'd like to extend a sincere <em>thank you</em> to everybody who pitched in to make typescript-eslint v6 possible.</p>
<ul>
<li>Ourselves on the maintenance team:<!-- -->
<ul>
<li><a href="https://github.com/armano2" target="_blank" rel="noopener noreferrer">Armano</a></li>
<li><a href="https://github.com/bradzacher" target="_blank" rel="noopener noreferrer">Brad Zacher</a></li>
<li><a href="https://github.com/JamesHenry" target="_blank" rel="noopener noreferrer">James Henry</a></li>
<li><a href="https://github.com/JoshuaKGoldberg" target="_blank" rel="noopener noreferrer">Josh Goldberg</a></li>
<li><a href="https://github.com/Josh-Cena" target="_blank" rel="noopener noreferrer">Joshua Chen</a></li>
</ul>
</li>
<li>Community contributors whose PRs were merged into the 6.0.0 release:<!-- -->
<ul>
<li><a href="https://github.com/bmish" target="_blank" rel="noopener noreferrer">Bryan Mishkin</a></li>
<li><a href="https://github.com/fisker" target="_blank" rel="noopener noreferrer">fisker Cheung</a></li>
<li><a href="https://github.com/juank1809" target="_blank" rel="noopener noreferrer">Juan García</a></li>
<li><a href="https://github.com/kball" target="_blank" rel="noopener noreferrer">Kevin Ball</a></li>
<li><a href="https://github.com/marekdedic" target="_blank" rel="noopener noreferrer">Marek Dědič</a></li>
<li><a href="https://github.com/Andarist" target="_blank" rel="noopener noreferrer">Mateusz Burzyński</a></li>
</ul>
</li>
<li>Community projects that worked with us to try out the reworked preset configs:<!-- -->
<ul>
<li><a href="https://github.com/withastro/astro/pull/7425" target="_blank" rel="noopener noreferrer">Astro</a></li>
<li><a href="https://github.com/babel/babel/pull/15716" target="_blank" rel="noopener noreferrer">Babel</a></li>
<li><a href="https://github.com/t3-oss/create-t3-app/pull/1476" target="_blank" rel="noopener noreferrer">create-t3-app</a></li>
<li><a href="https://github.com/trpc/trpc/pull/4541" target="_blank" rel="noopener noreferrer">trpc</a></li>
<li><a href="https://github.com/microsoft/TypeScript/pull/54693" target="_blank" rel="noopener noreferrer">TypeScript</a></li>
</ul>
</li>
</ul>
<p>See the <a href="https://github.com/typescript-eslint/typescript-eslint/milestone/8" target="_blank" rel="noopener noreferrer">v6.0.0 milestone</a> for the list of issues and associated merged pull requests.</p>
<h2 class="anchor anchorWithStickyNavbar_eAos" id="supporting-typescript-eslint">Supporting typescript-eslint<a href="https://typescript-eslint.io/blog/announcing-typescript-eslint-v6#supporting-typescript-eslint" class="hash-link" aria-label="Direct link to Supporting typescript-eslint" title="Direct link to Supporting typescript-eslint">​</a></h2>
<p>If you enjoyed this blog post and/or use typescript-eslint, please consider <a href="https://opencollective.com/typescript-eslint" target="_blank" rel="noopener noreferrer">supporting us on Open Collective</a>. We're a small volunteer team and could use your support to make the ESLint experience on TypeScript great. Thanks! 💖</p>]]></content:encoded>
            <category>breaking changes</category>
            <category>typescript-eslint</category>
            <category>v5</category>
            <category>v6</category>
        </item>
        <item>
            <title><![CDATA[Announcing typescript-eslint v6 Beta]]></title>
            <link>https://typescript-eslint.io/blog/announcing-typescript-eslint-v6-beta</link>
            <guid>https://typescript-eslint.io/blog/announcing-typescript-eslint-v6-beta</guid>
            <pubDate>Mon, 13 Mar 2023 00:00:00 GMT</pubDate>
            <description><![CDATA[Announcing the release of typescript-eslint's v6 beta, including its changes and timeline.]]></description>
            <content:encoded><![CDATA[<div class="theme-admonition theme-admonition-caution admonition_pzuZ alert alert--warning"><div class="admonitionHeading_uJho"><span class="admonitionIcon_vMH2"><svg viewBox="0 0 16 16"><path fill-rule="evenodd" d="M8.893 1.5c-.183-.31-.52-.5-.887-.5s-.703.19-.886.5L.138 13.499a.98.98 0 0 0 0 1.001c.193.31.53.501.886.501h13.964c.367 0 .704-.19.877-.5a1.03 1.03 0 0 0 .01-1.002L8.893 1.5zm.133 11.497H6.987v-2.003h2.039v2.003zm0-3.004H6.987V5.987h2.039v4.006z"></path></svg></span>Newer Information Available</div><div class="admonitionContent_gazR"><p>This blog post is now out of date, as we've released typescript-eslint v6! 🚀
Please see <a href="https://typescript-eslint.io/blog/announcing-typescript-eslint-v6">Announcing typescript-eslint v6</a> for the latest information.</p></div></div>
<p><a href="https://typescript-eslint.io/" target="_blank" rel="noopener noreferrer">typescript-eslint</a> is the tooling that enables standard JavaScript tools such as <a href="https://eslint.org/" target="_blank" rel="noopener noreferrer">ESLint</a> and <a href="https://prettier.io/" target="_blank" rel="noopener noreferrer">Prettier</a> 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! 🎉</p>
<p>Our plan for typescript-eslint v6 is to:</p>
<ol>
<li>Have users try out betas starting in early March of 2023</li>
<li>Respond to user feedback for the next 1-3 months</li>
<li>Release a stable version summer of 2023</li>
</ol>
<p>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 <a href="https://discord.gg/FSxKq8Tdyg" target="_blank" rel="noopener noreferrer">the typescript-eslint Discord</a>'s <code>#v6</code> channel!</p>
<h2 class="anchor anchorWithStickyNavbar_eAos" id="trying-out-v6">Trying Out v6<a href="https://typescript-eslint.io/blog/announcing-typescript-eslint-v6-beta#trying-out-v6" class="hash-link" aria-label="Direct link to Trying Out v6" title="Direct link to Trying Out v6">​</a></h2>
<p>Please do try out the typescript-eslint v6 beta!</p>
<h3 class="anchor anchorWithStickyNavbar_eAos" id="as-a-new-user">As A New User<a href="https://typescript-eslint.io/blog/announcing-typescript-eslint-v6-beta#as-a-new-user" class="hash-link" aria-label="Direct link to As A New User" title="Direct link to As A New User">​</a></h3>
<p>If you don't yet use typescript-eslint, you can go through our <a href="https://typescript-eslint.io/getting-started">configuration steps on the v6 <em>Getting Started</em> docs</a>.
It'll walk you through setting up typescript-eslint in a project.</p>
<p>To use v6 specifically, see the following section for an updated install command.</p>
<h3 class="anchor anchorWithStickyNavbar_eAos" id="as-an-existing-user">As An Existing User<a href="https://typescript-eslint.io/blog/announcing-typescript-eslint-v6-beta#as-an-existing-user" class="hash-link" aria-label="Direct link to As An Existing User" title="Direct link to As An Existing User">​</a></h3>
<p>If you already use typescript-eslint, you'll need to first replace your package's previous versions of <code>@typescript-eslint/eslint-plugin</code> and <code>@typescript-eslint/parser</code> with <code>@rc-v6</code> versions:</p>
<div class="language-shell codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockContent_m3Ux"><pre class="prism-code language-shell codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line"><span class="token function">npm</span><span class="token plain"> i @typescript-eslint/eslint-plugin@rc-v6 @typescript-eslint/parser@rc-v6 --save-dev</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>We highly recommend then basing your ESLint configuration on the reworked typescript-eslint <a href="https://typescript-eslint.io/blog/announcing-typescript-eslint-v6-beta#reworked-configuration-names">recommended configurations mentioned later in this post</a> — especially if it's been a while since you've reworked your linter config.</p>
<h2 class="anchor anchorWithStickyNavbar_eAos" id="user-facing-breaking-changes">User-Facing Breaking Changes<a href="https://typescript-eslint.io/blog/announcing-typescript-eslint-v6-beta#user-facing-breaking-changes" class="hash-link" aria-label="Direct link to User-Facing Breaking Changes" title="Direct link to User-Facing Breaking Changes">​</a></h2>
<p>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.</p>
<blockquote>
<p>⏳ 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.</p>
</blockquote>
<h3 class="anchor anchorWithStickyNavbar_eAos" id="reworked-configuration-names">Reworked Configuration Names<a href="https://typescript-eslint.io/blog/announcing-typescript-eslint-v6-beta#reworked-configuration-names" class="hash-link" aria-label="Direct link to Reworked Configuration Names" title="Direct link to Reworked Configuration Names">​</a></h3>
<p>The biggest configuration change in typescript-eslint v6 is that we've reworked the names of our <a href="https://typescript-eslint.io/users/configs">provided user configuration files</a>.
typescript-eslint v5 provided three recommended configurations:</p>
<ul>
<li><a href="https://typescript-eslint.io/users/configs#recommended"><code>recommended</code></a>: Recommended rules for code correctness that you can drop in without additional configuration.</li>
<li><a href="https://typescript-eslint.io/users/configs#recommended-requiring-type-checking"><code>recommended-requiring-type-checking</code></a>: Additional recommended rules that require type information.</li>
<li><a href="https://typescript-eslint.io/users/configs#strict"><code>strict</code></a>: Additional strict rules that can also catch bugs but are more opinionated than recommended rules.</li>
</ul>
<p>Those configurations worked well for most projects.
However, some users correctly noted two flaws in that approach:</p>
<ul>
<li>Strict rules that didn't require type checking were lumped in with those that did.</li>
<li><em>Stylistic</em> best practices were lumped in with rules that actually find bugs.</li>
</ul>
<p>As a result, we've reworked the configurations provided by typescript-eslint into these two groups:</p>
<ul>
<li>Functional rule configurations, for best best practices and code correctness:<!-- -->
<ul>
<li><strong><code>recommended</code></strong>: Recommended rules that you can drop in without additional configuration.</li>
<li><strong><code>recommended-type-checked</code></strong>:&nbsp;Additional recommended rules that require type information.</li>
<li><strong><code>strict</code></strong>: Additional strict rules that can also catch bugs but are more opinionated than recommended rules <em>(without type information)</em>.</li>
<li><strong><code>strict-type-checked</code></strong>: Additional strict rules that do require type information.</li>
</ul>
</li>
<li>Stylistic rule configurations, for consistent and predictable syntax usage:<!-- -->
<ul>
<li><strong><code>stylistic</code></strong>: Stylistic rules you can drop in without additional configuration.</li>
<li><strong><code>stylistic-type-checked</code></strong>: Additional stylistic rules that require type information.</li>
</ul>
</li>
</ul>
<blockquote>
<p><code>recommended-requiring-type-checking</code> is now an alias for <code>recommended-type-checked</code>.
The alias will be removed in a future major version.</p>
</blockquote>
<p>As of v6, we recommend that projects enable two configs from the above:</p>
<ul>
<li>If you are <em>not</em> using typed linting, enable <code>stylistic</code> and either <code>recommended</code> or <code>strict</code>, depending on how intensely you'd like your lint rules to scrutinize your code.</li>
<li>If you <em>are</em> using typed linting, enable <code>stylistic-type-checked</code> and either <code>recommended-type-checked</code> or <code>strict-type-checked</code>, depending on how intensely you'd like your lint rules to scrutinize your code.</li>
</ul>
<p>For example, a typical project that enables typed linting might have an ESLint configuration file that changes like:</p>
<div class="language-js codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockTitle_P25_">.eslintrc.cjs</div><div class="codeBlockContent_m3Ux"><pre class="prism-code language-js codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line"><span class="token plain">module</span><span class="token punctuation">.</span><span class="token property-access">exports</span><span class="token plain"> </span><span class="token operator">=</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token keyword">extends</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation">[</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">    </span><span class="token string">'eslint:recommended'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line code-block-removed-line"><span class="token plain">    </span><span class="token string">'plugin:@typescript-eslint/recommended'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line code-block-removed-line"><span class="token plain">    </span><span class="token string">'plugin:@typescript-eslint/recommended-requiring-type-checking'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line code-block-added-line"><span class="token plain">    </span><span class="token string">'plugin:@typescript-eslint/recommended-type-checked'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line code-block-added-line"><span class="token plain">    </span><span class="token string">'plugin:@typescript-eslint/stylistic-type-checked'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token punctuation">]</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token literal-property property">plugins</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation">[</span><span class="token string">'@typescript-eslint'</span><span class="token punctuation">]</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token literal-property property">parser</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'@typescript-eslint/parser'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token literal-property property">parserOptions</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line code-block-removed-line"><span class="token plain">    </span><span class="token literal-property property">project</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'./tsconfig.json'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line code-block-added-line"><span class="token plain">    </span><span class="token literal-property property">project</span><span class="token operator">:</span><span class="token plain"> </span><span class="token boolean">true</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">    </span><span class="token literal-property property">tsconfigRootDir</span><span class="token operator">:</span><span class="token plain"> __dirname</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token punctuation">}</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token literal-property property">root</span><span class="token operator">:</span><span class="token plain"> </span><span class="token boolean">true</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token punctuation">}</span><span class="token punctuation">;</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>See <a href="https://typescript-eslint.io/users/configs"><em>Configurations</em> on the v6 docs site preview</a> for the updated documentation on configurations provided by typescript-eslint.</p>
<p>For more information on these changes, see:</p>
<ul>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/discussions/6019" target="_blank" rel="noopener noreferrer">Configs: Have recommended/strict configs include lesser configs, and simplify type checked names</a> for the discussion leading up to these configuration changes.</li>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/pull/5251" target="_blank" rel="noopener noreferrer">feat(eslint-plugin): rework configs: recommended, strict, stylistic; -type-checked</a> for the pull request implementing the changes.</li>
</ul>
<h3 class="anchor anchorWithStickyNavbar_eAos" id="updated-configuration-rules">Updated Configuration Rules<a href="https://typescript-eslint.io/blog/announcing-typescript-eslint-v6-beta#updated-configuration-rules" class="hash-link" aria-label="Direct link to Updated Configuration Rules" title="Direct link to Updated Configuration Rules">​</a></h3>
<p>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 <a href="https://github.com/typescript-eslint/typescript-eslint/discussions/6014" target="_blank" rel="noopener noreferrer">Changes to configurations for 6.0.0</a> for a full list of the changes.</p>
<p>Please do try out the new rule configurations presets and let us know in that discussion!</p>
<div class="theme-admonition theme-admonition-tip admonition_pzuZ alert alert--success"><div class="admonitionHeading_uJho"><span class="admonitionIcon_vMH2"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>tip</div><div class="admonitionContent_gazR"><p>If your ESLint configuration contains many <code>rules</code> configurations, we suggest the following strategy to start anew:</p><ol>
<li>Remove all your rules configurations</li>
<li>Extend from the preset configs that make sense for you</li>
<li>Run ESLint on your project</li>
<li>In your ESLint configuration, turn off any rules creating errors that don't make sense for your project - with comments explaining why</li>
<li>In your ESLint configuration and/or with inline <code>eslint-disable</code> comments, turn off any rules creating too many errors for you to fix - with <em>"TODO"</em> comments linking to tracking issues/tickets to re-enable them</li>
</ol></div></div>
<p>Miscellaneous changes to all shared configurations include:</p>
<ul>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/pull/5381" target="_blank" rel="noopener noreferrer">fix(eslint-plugin): remove valid-typeof disable in eslint-recommended</a>: Removes the disabling of ESLint's <code>valid-typeof</code> rule from our preset configs.</li>
</ul>
<h3 class="anchor anchorWithStickyNavbar_eAos" id="rule-breaking-changes">Rule Breaking Changes<a href="https://typescript-eslint.io/blog/announcing-typescript-eslint-v6-beta#rule-breaking-changes" class="hash-link" aria-label="Direct link to Rule Breaking Changes" title="Direct link to Rule Breaking Changes">​</a></h3>
<div class="theme-admonition theme-admonition-caution admonition_pzuZ alert alert--warning"><div class="admonitionHeading_uJho"><span class="admonitionIcon_vMH2"><svg viewBox="0 0 16 16"><path fill-rule="evenodd" d="M8.893 1.5c-.183-.31-.52-.5-.887-.5s-.703.19-.886.5L.138 13.499a.98.98 0 0 0 0 1.001c.193.31.53.501.886.501h13.964c.367 0 .704-.19.877-.5a1.03 1.03 0 0 0 .01-1.002L8.893 1.5zm.133 11.497H6.987v-2.003h2.039v2.003zm0-3.004H6.987V5.987h2.039v4.006z"></path></svg></span>Newer Information Available</div><div class="admonitionContent_gazR"><p>This section is now out of date, as we've released typescript-eslint v6! 🚀
Please see <a href="https://typescript-eslint.io/blog/announcing-typescript-eslint-v6#rule-breaking-changes">Announcing typescript-eslint v6 &gt; Rule Breaking Changes</a> for the latest information.</p></div></div>
<p>Several rules were changed in significant enough ways to be considered breaking changes:</p>
<ul>
<li>Previously deprecated rules are deleted (<a href="https://github.com/typescript-eslint/typescript-eslint/pull/6112" target="_blank" rel="noopener noreferrer">chore(eslint-plugin): remove deprecated rules for v6</a>):<!-- -->
<ul>
<li><code>@typescript-eslint/no-duplicate-imports</code></li>
<li><code>@typescript-eslint/no-implicit-any-catch</code></li>
<li><code>@typescript-eslint/no-parameter-properties</code></li>
<li><code>@typescript-eslint/sort-type-union-intersection-members</code></li>
</ul>
</li>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/pull/5234" target="_blank" rel="noopener noreferrer">feat(eslint-plugin): [prefer-nullish-coalescing]: add support for assignment expressions</a>: Enhances the <a href="https://typescript-eslint.io/rules/prefer-nullish-coalescing"><code>@typescript-eslint/prefer-nullish-coalescing</code></a> rule to also check <code>||=</code> expressions.</li>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/pull/6240" target="_blank" rel="noopener noreferrer">feat(eslint-plugin): [prefer-optional-chain] use type checking for strict falsiness</a>: Rewrites the <a href="https://typescript-eslint.io/rules/prefer-optional-chain"><code>@typescript-eslint/prefer-optional-chain</code></a> rule to fix numerous false positives, at the cost of making it require type information.</li>
</ul>
<h3 class="anchor anchorWithStickyNavbar_eAos" id="tooling-breaking-changes">Tooling Breaking Changes<a href="https://typescript-eslint.io/blog/announcing-typescript-eslint-v6-beta#tooling-breaking-changes" class="hash-link" aria-label="Direct link to Tooling Breaking Changes" title="Direct link to Tooling Breaking Changes">​</a></h3>
<div class="theme-admonition theme-admonition-caution admonition_pzuZ alert alert--warning"><div class="admonitionHeading_uJho"><span class="admonitionIcon_vMH2"><svg viewBox="0 0 16 16"><path fill-rule="evenodd" d="M8.893 1.5c-.183-.31-.52-.5-.887-.5s-.703.19-.886.5L.138 13.499a.98.98 0 0 0 0 1.001c.193.31.53.501.886.501h13.964c.367 0 .704-.19.877-.5a1.03 1.03 0 0 0 .01-1.002L8.893 1.5zm.133 11.497H6.987v-2.003h2.039v2.003zm0-3.004H6.987V5.987h2.039v4.006z"></path></svg></span>Newer Information Available</div><div class="admonitionContent_gazR"><p>This section is now out of date, as we've released typescript-eslint v6! 🚀
Please see <a href="https://typescript-eslint.io/blog/announcing-typescript-eslint-v6#tooling-breaking-changes">Announcing typescript-eslint v6 &gt; Tooling Breaking Changes</a> for the latest information.</p></div></div>
<ul>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/pull/5890" target="_blank" rel="noopener noreferrer">feat(typescript-estree): deprecate createDefaultProgram</a>: Renames <code>createDefaultProgram</code> to <code>deprecated__createDefaultProgram</code>, with associated <code>@deprecated</code> TSDoc tags and warnings.</li>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/pull/5918" target="_blank" rel="noopener noreferrer">feat: drop support for node v12</a></li>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/pull/7022" target="_blank" rel="noopener noreferrer">feat: drop support for node v14</a></li>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/issues/6923" target="_blank" rel="noopener noreferrer">feat: bump minimum supported TS version to 4.3.5</a>: this matches <a href="https://github.com/DefinitelyTyped/DefinitelyTyped#support-window" target="_blank" rel="noopener noreferrer">DefinitelyTyped's 2-year support window</a>.</li>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/pull/5972" target="_blank" rel="noopener noreferrer">chore: drop support for ESLint v6</a></li>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/pull/4436" target="_blank" rel="noopener noreferrer">feat(eslint-plugin): [prefer-readonly-parameter-types] added an optional type allowlist</a>: changes the public <code>isTypeReadonlyArrayOrTuple</code> function's first argument from a <code>checker: ts.TypeChecker</code> to a full <code>program: ts.Program</code></li>
</ul>
<h2 class="anchor anchorWithStickyNavbar_eAos" id="developer-facing-changes">Developer-Facing Changes<a href="https://typescript-eslint.io/blog/announcing-typescript-eslint-v6-beta#developer-facing-changes" class="hash-link" aria-label="Direct link to Developer-Facing Changes" title="Direct link to Developer-Facing Changes">​</a></h2>
<p>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.</p>
<div class="theme-admonition theme-admonition-tip admonition_pzuZ alert alert--success"><div class="admonitionHeading_uJho"><span class="admonitionIcon_vMH2"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>tip</div><div class="admonitionContent_gazR"><p>If you're having trouble working with the changes, please let us know on <a href="https://discord.gg/FSxKq8Tdyg" target="_blank" rel="noopener noreferrer">the typescript-eslint Discord</a>'s <code>#v6</code> channel!</p></div></div>
<h3 class="anchor anchorWithStickyNavbar_eAos" id="type-checker-wrapper-apis">Type Checker Wrapper APIs<a href="https://typescript-eslint.io/blog/announcing-typescript-eslint-v6-beta#type-checker-wrapper-apis" class="hash-link" aria-label="Direct link to Type Checker Wrapper APIs" title="Direct link to Type Checker Wrapper APIs">​</a></h3>
<p>As described in our <a href="https://typescript-eslint.io/blog/asts-and-typescript-eslint">ASTs and typescript-eslint</a> 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:</p>
<div class="language-ts codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockTitle_P25_">custom-rule-with-v5.ts</div><div class="codeBlockContent_m3Ux"><pre class="prism-code language-ts codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line"><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token comment">// ...</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token function">create</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">    </span><span class="token keyword">const</span><span class="token plain"> services </span><span class="token operator">=</span><span class="token plain"> util</span><span class="token punctuation">.</span><span class="token function">getParserServices</span><span class="token punctuation">(</span><span class="token plain">context</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">    </span><span class="token keyword">const</span><span class="token plain"> checker </span><span class="token operator">=</span><span class="token plain"> services</span><span class="token punctuation">.</span><span class="token plain">program</span><span class="token punctuation">.</span><span class="token function">getTypeChecker</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">    </span><span class="token keyword">const</span><span class="token plain"> tsNode </span><span class="token operator">=</span><span class="token plain"> services</span><span class="token punctuation">.</span><span class="token plain">esTreeNodeToTSNodeMap</span><span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token plain">esNode</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">    </span><span class="token keyword">const</span><span class="token plain"> type </span><span class="token operator">=</span><span class="token plain"> checker</span><span class="token punctuation">.</span><span class="token function">getTypeAtLocation</span><span class="token punctuation">(</span><span class="token plain">node</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line"><span class="token plain">    </span><span class="token comment">// ...</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token punctuation">}</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token comment">// ...</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token punctuation">}</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>How cumbersome, just to call to a single method (<code>getTypeAtLocation</code>) on the TypeScript API!</p>
<p>In typescript-eslint v6, we've added a set of wrapper APIs on the <code>services: ParserServices</code> object that act as shortcuts for commonly used TypeScript APIs including <code>getTypeAtLocation</code>:</p>
<div class="language-ts codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockTitle_P25_">custom-rule-with-v6.ts</div><div class="codeBlockContent_m3Ux"><pre class="prism-code language-ts codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line"><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token comment">// ...</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token function">create</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">    </span><span class="token keyword">const</span><span class="token plain"> services </span><span class="token operator">=</span><span class="token plain"> util</span><span class="token punctuation">.</span><span class="token function">getParserServices</span><span class="token punctuation">(</span><span class="token plain">context</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">    </span><span class="token keyword">const</span><span class="token plain"> type </span><span class="token operator">=</span><span class="token plain"> services</span><span class="token punctuation">.</span><span class="token function">getTypeAtLocation</span><span class="token punctuation">(</span><span class="token plain">node</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line"><span class="token plain">    </span><span class="token comment">// ...</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token punctuation">}</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token comment">// ...</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token punctuation">}</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>For now, the available wrapper APIs are:</p>
<ul>
<li><code>getSymbolAtLocation</code>: passes an ESTree's equivalent TypeScript node to <code>checker.getSymbolAtLocation</code></li>
<li><code>getTypeAtLocation</code>: passes an ESTree node's equivalent TypeScript node to <code>checker.getTypeAtLocation</code></li>
</ul>
<p>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.</p>
<div class="theme-admonition theme-admonition-caution admonition_pzuZ alert alert--warning"><div class="admonitionHeading_uJho"><span class="admonitionIcon_vMH2"><svg viewBox="0 0 16 16"><path fill-rule="evenodd" d="M8.893 1.5c-.183-.31-.52-.5-.887-.5s-.703.19-.886.5L.138 13.499a.98.98 0 0 0 0 1.001c.193.31.53.501.886.501h13.964c.367 0 .704-.19.877-.5a1.03 1.03 0 0 0 .01-1.002L8.893 1.5zm.133 11.497H6.987v-2.003h2.039v2.003zm0-3.004H6.987V5.987h2.039v4.006z"></path></svg></span>Newer Information Available</div><div class="admonitionContent_gazR"><p>Rules can still retrieve their full backing TypeScript type checker with <code>services.program.getTypeChecker()</code>.
This can be necessary for TypeScript APIs not wrapped by the parser services.</p></div></div>
<p>See <a href="https://typescript-eslint.io/developers/custom-rules"><em>Custom Rules</em> on the v6 docs site preview</a> for the updated documentation on creating custom rules with typescript-eslint.</p>
<h3 class="anchor anchorWithStickyNavbar_eAos" id="ast-breaking-changes">AST Breaking Changes<a href="https://typescript-eslint.io/blog/announcing-typescript-eslint-v6-beta#ast-breaking-changes" class="hash-link" aria-label="Direct link to AST Breaking Changes" title="Direct link to AST Breaking Changes">​</a></h3>
<p>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.</p>
<ul>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/pull/5252" target="_blank" rel="noopener noreferrer">feat: made BaseNode.parent non-optional</a>: makes the <code>node.parent</code> property on AST nodes non-optional (<code>TSESTree.Node</code> instead of <code>TSESTree.Node | undefined</code>).</li>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/pull/6257" target="_blank" rel="noopener noreferrer">fix(ast-spec): correct some incorrect ast types</a>: applies the following changes to correct erroneous types of AST node properties:<!-- -->
<ul>
<li><code>ArrayExpressions</code>'s <code>elements</code> property can now include <code>null</code> (i.e. is now <code>(Expression | SpreadElement | null)[]</code>), for the case of sparse arrays (e.g. <code>[1, , 3]</code>).</li>
<li><code>MemberExpression</code>'s <code>object</code> property is now <code>Expression</code>, not <code>LeftHandSideExpression</code>.</li>
<li><code>ObjectLiteralElement</code> no longer allows for <code>MethodDefinition</code>.</li>
</ul>
</li>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/pull/5885" target="_blank" rel="noopener noreferrer">fix(typescript-estree): wrap import = declaration in an export node</a>: Exported <code>TSImportEqualsDeclaration</code> nodes are now wrapped in an <code>ExportNamedDeclaration</code> node instead of having <code>.isExport = true</code> property.</li>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/pull/6243" target="_blank" rel="noopener noreferrer">fix(ast-spec): remove more invalid properties</a>: applies the following changes to remove invalid properties from AST nodes:<!-- -->
<ul>
<li><code>MethodDefinitionBase</code> no longer has a <code>typeParameters</code> property.</li>
<li><code>TSIndexSignature</code>, <code>TSMethodSignature</code>, and <code>TSPropertySignatureBase</code> no longer have an <code>export</code> property.</li>
<li><code>TSPropertySignatureBase</code> no longer has an <code>initializer</code> property.</li>
</ul>
</li>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/pull/6272" target="_blank" rel="noopener noreferrer">fix(typescript-estree): account for namespace nesting in AST conversion</a>: Namespaces with qualified names like <code>Abc.Def</code> now use a <code>TSQualifiedName</code> node, instead of a nested body structure.</li>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/pull/4863" target="_blank" rel="noopener noreferrer">feat: remove semantically invalid properties from TSEnumDeclaration, TSInterfaceDeclaration and TSModuleDeclaration</a>: Removes some properties from those AST node types that should generally not have existed to begin with.</li>
</ul>
<h3 class="anchor anchorWithStickyNavbar_eAos" id="errors-on-invalid-ast-parsing">Errors on Invalid AST Parsing<a href="https://typescript-eslint.io/blog/announcing-typescript-eslint-v6-beta#errors-on-invalid-ast-parsing" class="hash-link" aria-label="Direct link to Errors on Invalid AST Parsing" title="Direct link to Errors on Invalid AST Parsing">​</a></h3>
<div class="theme-admonition theme-admonition-caution admonition_pzuZ alert alert--warning"><div class="admonitionHeading_uJho"><span class="admonitionIcon_vMH2"><svg viewBox="0 0 16 16"><path fill-rule="evenodd" d="M8.893 1.5c-.183-.31-.52-.5-.887-.5s-.703.19-.886.5L.138 13.499a.98.98 0 0 0 0 1.001c.193.31.53.501.886.501h13.964c.367 0 .704-.19.877-.5a1.03 1.03 0 0 0 .01-1.002L8.893 1.5zm.133 11.497H6.987v-2.003h2.039v2.003zm0-3.004H6.987V5.987h2.039v4.006z"></path></svg></span>Newer Information Available</div><div class="admonitionContent_gazR"><p>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.</p></div></div>
<p>The <code>@typescript-eslint/typescript-estree</code> 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.</p>
<p>For example, this snippet of TypeScript code creates a <code>ClassDeclaration</code> whose <code>id</code> is <code>null</code>:</p>
<div class="language-ts codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockContent_m3Ux"><pre class="prism-code language-ts codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line"><span class="token keyword">export</span><span class="token plain"> </span><span class="token keyword">class</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token punctuation">}</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>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.</p>
<p><code>@typescript-eslint/typescript-estree</code> will now throw an error when it encounters a known invalid AST such as the <code>export class {}</code> example.
This is generally the correct behavior for most parsing contexts so downstream tools don't have to work with a potentially invalid AST.</p>
<p>For consumers that don't want the updated behavior of throwing on invalid ASTs, a new <code>allowInvalidAST</code> 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.</p>
<p>For more information, see:</p>
<ul>
<li>The backing issue: <a href="https://github.com/typescript-eslint/typescript-eslint/issues/1852" target="_blank" rel="noopener noreferrer">Parsing: strictly enforce the produced AST matches the spec and enforce most "error recovery" parsing errors</a></li>
<li>The implementing pull request: <a href="https://github.com/typescript-eslint/typescript-eslint/pull/6247" target="_blank" rel="noopener noreferrer">feat(typescript-estree): added allowInvalidAST option to throw on invalid tokens</a></li>
</ul>
<h3 class="anchor anchorWithStickyNavbar_eAos" id="standalone-ruletester-package">Standalone <code>RuleTester</code> package<a href="https://typescript-eslint.io/blog/announcing-typescript-eslint-v6-beta#standalone-ruletester-package" class="hash-link" aria-label="Direct link to standalone-ruletester-package" title="Direct link to standalone-ruletester-package">​</a></h3>
<p>Previously we provided a version of ESLint's <code>RuleTester</code> class from <code>@typescript-eslint/utils/eslint-utils</code>. 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.</p>
<p>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.</p>
<p>In v6 we have extracted this into its own package - <code>@typescript-eslint/rule-tester</code>. 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:</p>
<div class="language-ts codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockContent_m3Ux"><pre class="prism-code language-ts codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line code-block-removed-line"><span class="token keyword">import</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"> TSESLint </span><span class="token punctuation">}</span><span class="token plain"> </span><span class="token keyword">from</span><span class="token plain"> </span><span class="token string">'@typescript-eslint/utils'</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line code-block-added-line"><span class="token plain"></span><span class="token keyword">import</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"> RuleTester </span><span class="token punctuation">}</span><span class="token plain"> </span><span class="token keyword">from</span><span class="token plain"> </span><span class="token string">'@typescript-eslint/rule-tester'</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token keyword">import</span><span class="token plain"> rule </span><span class="token keyword">from</span><span class="token plain"> </span><span class="token string">'../src/rules/my-rule'</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line code-block-removed-line"><span class="token plain"></span><span class="token keyword">const</span><span class="token plain"> ruleTester </span><span class="token operator">=</span><span class="token plain"> </span><span class="token keyword">new</span><span class="token plain"> </span><span class="token class-name">TSESLint</span><span class="token punctuation">.</span><span class="token function">RuleTester</span><span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line code-block-added-line"><span class="token plain"></span><span class="token keyword">const</span><span class="token plain"> ruleTester </span><span class="token operator">=</span><span class="token plain"> </span><span class="token keyword">new</span><span class="token plain"> </span><span class="token class-name">RuleTester</span><span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  parser</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'@typescript-eslint/parser'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line"><span class="token plain">ruleTester</span><span class="token punctuation">.</span><span class="token function">run</span><span class="token punctuation">(</span><span class="token string">'my-rule'</span><span class="token punctuation">,</span><span class="token plain"> rule</span><span class="token punctuation">,</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"> </span><span class="token comment">/* ... */</span><span class="token plain"> </span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Breaking changes:</p>
<ul>
<li>Previously if you set <code>parserOptions.ecmaFeatures.jsx = true</code> the rule tester would attempt to look for a fixture named <code>file.tsx</code>. Now instead the rule tester will look for a file named <code>react.tsx</code>.<!-- -->
<ul>
<li>The previous behavior was incorrect because it would encourage you to have both <code>file.ts</code> and <code>file.tsx</code> and TypeScript would ignore one of those files, causing weird breakages in tests.</li>
<li>You can control the default filenames by passing <code>defaultFilenames</code> to the <code>RuleTester</code> constructor.</li>
</ul>
</li>
</ul>
<p>New features:</p>
<ul>
<li><code>skip: boolean</code> - the inverse option of <code>only: boolean</code>. When <code>true</code> we will use your test framework's test skip functionality (<code>it.skip</code>) 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.</li>
<li>Dependency version filtering. It's useful to test your rule against multiple versions of your dependencies to ensure it doesn't break on older versions. However in some cases certain tests will not work on older versions of some dependencies due to features that didn't exist until recently - for example a test might use newer syntax that didn't exist in an older version of TypeScript. Our rule tester includes options that allow you to declare the allowed version ranges for a test so that it is automatically skipped when necessary.</li>
</ul>
<p>For more information on the package, <a href="https://typescript-eslint.io/packages/rule-tester">see the <code>rule-tester</code> package documentation</a>.</p>
<h3 class="anchor anchorWithStickyNavbar_eAos" id="other-developer-facing-breaking-changes">Other Developer-Facing Breaking Changes<a href="https://typescript-eslint.io/blog/announcing-typescript-eslint-v6-beta#other-developer-facing-breaking-changes" class="hash-link" aria-label="Direct link to Other Developer-Facing Breaking Changes" title="Direct link to Other Developer-Facing Breaking Changes">​</a></h3>
<div class="theme-admonition theme-admonition-caution admonition_pzuZ alert alert--warning"><div class="admonitionHeading_uJho"><span class="admonitionIcon_vMH2"><svg viewBox="0 0 16 16"><path fill-rule="evenodd" d="M8.893 1.5c-.183-.31-.52-.5-.887-.5s-.703.19-.886.5L.138 13.499a.98.98 0 0 0 0 1.001c.193.31.53.501.886.501h13.964c.367 0 .704-.19.877-.5a1.03 1.03 0 0 0 .01-1.002L8.893 1.5zm.133 11.497H6.987v-2.003h2.039v2.003zm0-3.004H6.987V5.987h2.039v4.006z"></path></svg></span>Newer Information Available</div><div class="admonitionContent_gazR"><p>This section is now out of date, as we've released typescript-eslint v6! 🚀
Please see <a href="https://typescript-eslint.io/blog/announcing-typescript-eslint-v6#other-developer-facing-breaking-changes">Announcing typescript-eslint v6 &gt; Other Developer-Facing Breaking Changes</a> for the latest information.</p></div></div>
<ul>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/pull/5036" target="_blank" rel="noopener noreferrer">fix(utils): removed TRuleListener generic from the createRule</a>: Makes <code>createRule</code>-created rules more portable in the type system.</li>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/pull/5256" target="_blank" rel="noopener noreferrer">feat(utils): remove (ts-)eslint-scope types</a>: Removes no-longer-useful <code>TSESLintScope</code> types from the <code>@typescript-eslint/utils</code> package. Use <code>@typescript-eslint/scope-manager</code> directly instead.</li>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/pull/5384" target="_blank" rel="noopener noreferrer">fix: rename typeParameters to typeArguments where needed</a>: corrects the names of AST properties that were called <em>parameters</em> instead of <em>arguments</em>.<!-- -->
<ul>
<li>To recap the terminology:<!-- -->
<ul>
<li>An <em>argument</em> is something you provide to a recipient, such as a type provided explicitly to a call expression.</li>
<li>A <em>parameter</em> is how the recipient receives what you provide, such as a function declaration's generic type parameter.</li>
</ul>
</li>
</ul>
</li>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/issues/6469" target="_blank" rel="noopener noreferrer">Enhancement: Add test-only console warnings to deprecated AST properties</a>: The properties will include a <code>console.log</code> that triggers only in test environments, to encourage developers to move off of them.</li>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/pull/5889" target="_blank" rel="noopener noreferrer">feat(scope-manager): ignore ECMA version</a>: <code>@typescript-eslint/scope-manager</code> no longer includes properties referring to <code>ecmaVersion</code>, <code>isES6</code>, or other ECMA versioning options. It instead now always assumes ESNext.</li>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/pull/6066" target="_blank" rel="noopener noreferrer">feat: remove partial type-information program</a>: When user configurations don't provide a <code>parserOptions.project</code>, parser services will no longer include a <code>program</code> with incomplete type information. <code>program</code> will be <code>null</code> instead.<!-- -->
<ul>
<li>As a result, the <code>errorOnTypeScriptSyntacticAndSemanticIssues</code> option will no longer be allowed if <code>parserOptions.project</code> is not provided.</li>
</ul>
</li>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/pull/6468" target="_blank" rel="noopener noreferrer">feat: remove experimental-utils</a>: The <code>@typescript-eslint/experimental-utils</code> package has since been renamed to <code>@typescript-eslint/utils</code>.</li>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/pull/6274" target="_blank" rel="noopener noreferrer">feat(typescript-estree): remove optionality from AST boolean properties</a>: Switches most AST properties marked as <code>?: boolean</code> to <code>: boolean</code>, as well as some properties marked as <code>?:</code> optional to <code>| undefined</code>. This results in more predictable AST node object shapes.</li>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/pull/6242" target="_blank" rel="noopener noreferrer">chore(typescript-estree): remove visitor-keys backwards compat export</a>: <code>visitorKeys</code> can now only be imported from <code>@typescript-eslint/visitor-keys</code>. Previously it was also re-exported by <code>@typescript-eslint/utils</code>.</li>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/pull/6458" target="_blank" rel="noopener noreferrer">feat: add package.json exports for public packages</a>: <code>@typescript-eslint/*</code> packages now use <code>exports</code> to prevent importing internal file paths.</li>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/pull/6963" target="_blank" rel="noopener noreferrer">feat: fork json schema types for better compat with ESLint rule validation #6963</a>: <code>@typescript-eslint/utils</code> now exports a more strict version of <code>JSONSchema4</code> types, which are more strict in type checking rule options types</li>
</ul>
<h2 class="anchor anchorWithStickyNavbar_eAos" id="appreciation">Appreciation<a href="https://typescript-eslint.io/blog/announcing-typescript-eslint-v6-beta#appreciation" class="hash-link" aria-label="Direct link to Appreciation" title="Direct link to Appreciation">​</a></h2>
<p>We'd like to extend a sincere <em>thank you</em> to everybody who pitched in to make typescript-eslint v6 possible.</p>
<ul>
<li>Ourselves on the maintenance team:<!-- -->
<ul>
<li><a href="https://github.com/armano2" target="_blank" rel="noopener noreferrer">Armano</a></li>
<li><a href="https://github.com/bradzacher" target="_blank" rel="noopener noreferrer">Brad Zacher</a></li>
<li><a href="https://github.com/JamesHenry" target="_blank" rel="noopener noreferrer">James Henry</a></li>
<li><a href="https://github.com/JoshuaKGoldberg" target="_blank" rel="noopener noreferrer">Josh Goldberg</a></li>
<li><a href="https://github.com/Josh-Cena" target="_blank" rel="noopener noreferrer">Joshua Chen</a></li>
</ul>
</li>
<li>Community contributors whose PRs were merged into the 6.0.0 release:<!-- -->
<ul>
<li><a href="https://github.com/bmish" target="_blank" rel="noopener noreferrer">Bryan Mishkin</a></li>
<li><a href="https://github.com/fisker" target="_blank" rel="noopener noreferrer">fisker Cheung</a></li>
<li><a href="https://github.com/juank1809" target="_blank" rel="noopener noreferrer">Juan García</a></li>
<li><a href="https://github.com/kball" target="_blank" rel="noopener noreferrer">Kevin Ball</a></li>
<li><a href="https://github.com/marekdedic" target="_blank" rel="noopener noreferrer">Marek Dědič</a></li>
<li><a href="https://github.com/Andarist" target="_blank" rel="noopener noreferrer">Mateusz Burzyński</a></li>
</ul>
</li>
</ul>
<p>See the <a href="https://github.com/typescript-eslint/typescript-eslint/milestone/8" target="_blank" rel="noopener noreferrer">v6.0.0 milestone</a> for the list of issues and associated merged pull requests.</p>
<h2 class="anchor anchorWithStickyNavbar_eAos" id="supporting-typescript-eslint">Supporting typescript-eslint<a href="https://typescript-eslint.io/blog/announcing-typescript-eslint-v6-beta#supporting-typescript-eslint" class="hash-link" aria-label="Direct link to Supporting typescript-eslint" title="Direct link to Supporting typescript-eslint">​</a></h2>
<p>If you enjoyed this blog post and/or use typescript-eslint, please consider <a href="https://opencollective.com/typescript-eslint" target="_blank" rel="noopener noreferrer">supporting us on Open Collective</a>. We're a small volunteer team and could use your support to make the ESLint experience on TypeScript great. Thanks! 💖</p>]]></content:encoded>
            <category>breaking changes</category>
            <category>typescript-eslint</category>
            <category>v5</category>
            <category>v6</category>
        </item>
        <item>
            <title><![CDATA[Consistent Type Imports and Exports: Why and How]]></title>
            <link>https://typescript-eslint.io/blog/consistent-type-imports-and-exports-why-and-how</link>
            <guid>https://typescript-eslint.io/blog/consistent-type-imports-and-exports-why-and-how</guid>
            <pubDate>Fri, 24 Feb 2023 00:00:00 GMT</pubDate>
            <description><![CDATA[Why enforcing TypeScript imports use the `type` modifier when possible benefits some project setups.]]></description>
            <content:encoded><![CDATA[<p><code>import</code> and <code>export</code> statements are core features of the JavaScript language.
They were added as part of the <a href="https://nodejs.org/api/esm.html#modules-ecmascript-modules" target="_blank" rel="noopener noreferrer">ECMAScript Modules (ESM)</a> specification, and now are generally available in most mainstream JavaScript environments, including all evergreen browsers and Node.js.</p>
<p>When writing TypeScript code with ESM, it can sometimes be desirable to import or export a type only in the type system.
Code may wish to refer to a <em>type</em>, but not actually import or export a corresponding <em>value</em>.</p>
<p>Type-only imports and exports are not emitted as runtime code when code is transpiled to JavaScript.
This brings up two questions:</p>
<ul>
<li>Why would you want to use these type-only imports and exports?</li>
<li>How can you enforce a project use them whenever necessary?</li>
</ul>
<p>Let's dig in!</p>
<h2 class="anchor anchorWithStickyNavbar_eAos" id="recap-type-only-imports-and-exports">Recap: Type-Only Imports and Exports<a href="https://typescript-eslint.io/blog/consistent-type-imports-and-exports-why-and-how#recap-type-only-imports-and-exports" class="hash-link" aria-label="Direct link to Recap: Type-Only Imports and Exports" title="Direct link to Recap: Type-Only Imports and Exports">​</a></h2>
<p>TypeScript 3.8 <a href="https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-8.html#type-only-imports-and-export" target="_blank" rel="noopener noreferrer">added type-only imports and exports</a> to the TypeScript language:</p>
<div class="language-ts codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockContent_m3Ux"><pre class="prism-code language-ts codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line"><span class="token keyword">import</span><span class="token plain"> </span><span class="token keyword">type</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"> SomeThing </span><span class="token punctuation">}</span><span class="token plain"> </span><span class="token keyword">from</span><span class="token plain"> </span><span class="token string">'./some-module.js'</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token keyword">export</span><span class="token plain"> </span><span class="token keyword">type</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"> SomeThing </span><span class="token punctuation">}</span><span class="token punctuation">;</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>The key difference with <code>export type</code> and <code>import type</code> is that they <em>do not represent runtime code</em>.
Attempting to use a <em>value</em> imported as only a <em>type</em> in runtime code will cause a TypeScript error:</p>
<div class="language-ts codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockContent_m3Ux"><pre class="prism-code language-ts codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line"><span class="token keyword">import</span><span class="token plain"> </span><span class="token keyword">type</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"> SomeThing </span><span class="token punctuation">}</span><span class="token plain"> </span><span class="token keyword">from</span><span class="token plain"> </span><span class="token string">'./some-module.js'</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token keyword">new</span><span class="token plain"> </span><span class="token class-name">SomeThing</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token comment">//  ~~~~~~~~~</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token comment">// 'SomeThing' cannot be used as a value</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token comment">// because it was imported using 'import type'.</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>TypeScript 4.5 also added <a href="https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-5.html#type-modifiers-on-import-names" target="_blank" rel="noopener noreferrer">inline type qualifiers</a>, which allow for indicating that only some specifiers in a statement should be type-system-only:</p>
<div class="language-ts codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockContent_m3Ux"><pre class="prism-code language-ts codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line"><span class="token keyword">import</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"> </span><span class="token keyword">type</span><span class="token plain"> </span><span class="token class-name">SomeType</span><span class="token punctuation">,</span><span class="token plain"> SomeValue </span><span class="token punctuation">}</span><span class="token plain"> </span><span class="token keyword">from</span><span class="token plain"> </span><span class="token string">'./some-module.js'</span><span class="token punctuation">;</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<h2 class="anchor anchorWithStickyNavbar_eAos" id="benefits-of-enforcing-type-only-importsexports">Benefits of Enforcing Type-only Imports/Exports<a href="https://typescript-eslint.io/blog/consistent-type-imports-and-exports-why-and-how#benefits-of-enforcing-type-only-importsexports" class="hash-link" aria-label="Direct link to Benefits of Enforcing Type-only Imports/Exports" title="Direct link to Benefits of Enforcing Type-only Imports/Exports">​</a></h2>
<h3 class="anchor anchorWithStickyNavbar_eAos" id="avoiding-unintentional-side-effects">Avoiding Unintentional Side Effects<a href="https://typescript-eslint.io/blog/consistent-type-imports-and-exports-why-and-how#avoiding-unintentional-side-effects" class="hash-link" aria-label="Direct link to Avoiding Unintentional Side Effects" title="Direct link to Avoiding Unintentional Side Effects">​</a></h3>
<p>Some modules in code may cause <em>side effects</em>: code that is run when the module is imported and causes changes outside the module.
Common examples of side effects include sending network requests via <code>fetch</code> or creating DOM stylesheets.</p>
<p>When projects include modules that cause side effects, the order of module imports matters.
For example, some projects import the types of side-effect-causing modules in code that needs to run before those side effects.</p>
<h3 class="anchor anchorWithStickyNavbar_eAos" id="isolated-module-transpilation">Isolated Module Transpilation<a href="https://typescript-eslint.io/blog/consistent-type-imports-and-exports-why-and-how#isolated-module-transpilation" class="hash-link" aria-label="Direct link to Isolated Module Transpilation" title="Direct link to Isolated Module Transpilation">​</a></h3>
<p>Import statements that only import types are generally removed when the TypeScript compiler transpiles TypeScript syntax to JavaScript syntax.
The built-in TypeScript compiler is able to do so because it includes a type checker that knows which imports are of types and/or values.</p>
<p>But, some projects use transpilers such as Babel, SWC, or Vite that don't have access to type information.
These transpilers are sometimes referred to as <em>isolated module transpilers</em> because they effectively transpile each module in isolation from other modules.
Isolated module transpilers can't know whether an import is of a type, a value, or both.</p>
<p>Take this file with exactly three lines of code:</p>
<div class="language-ts codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockContent_m3Ux"><pre class="prism-code language-ts codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line"><span class="token comment">// Is SomeThing a class? A type? A variable?</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token comment">// Just from this file, we don't know! 😫</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token keyword">import</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"> SomeThing </span><span class="token punctuation">}</span><span class="token plain"> </span><span class="token keyword">from</span><span class="token plain"> </span><span class="token string">'./may-include-side-effects.js'</span><span class="token punctuation">;</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>If that <code>./may-include-side-effects.js</code> module includes side effects, keeping or removing the import can have very different runtime behaviors in the project.
Indicating in code which values are type-only can be necessary for transpilers that don't have access to TypeScript's type system to know whether to keep or remove the import.</p>
<div class="language-ts codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockContent_m3Ux"><pre class="prism-code language-ts codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line"><span class="token comment">// Now we know this file's SomeThing is only used as a type.</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token comment">// We can remove this import in transpiled JavaScript syntax.</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token keyword">import</span><span class="token plain"> </span><span class="token keyword">type</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"> SomeThing </span><span class="token punctuation">}</span><span class="token plain"> </span><span class="token keyword">from</span><span class="token plain"> </span><span class="token string">'./may-include-side-effects.js'</span><span class="token punctuation">;</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<h2 class="anchor anchorWithStickyNavbar_eAos" id="enforcing-with-typescript-eslint">Enforcing With typescript-eslint<a href="https://typescript-eslint.io/blog/consistent-type-imports-and-exports-why-and-how#enforcing-with-typescript-eslint" class="hash-link" aria-label="Direct link to Enforcing With typescript-eslint" title="Direct link to Enforcing With typescript-eslint">​</a></h2>
<p>typescript-eslint provides two ESLint rules that can standardize using (or not using) type-only exports and imports:</p>
<ul>
<li><a href="https://typescript-eslint.io/rules/consistent-type-exports"><code>@typescript-eslint/consistent-type-exports</code></a>: Enforce consistent usage of type exports.</li>
<li><a href="https://typescript-eslint.io/rules/consistent-type-imports"><code>@typescript-eslint/consistent-type-imports</code></a>: Enforce consistent usage of type imports.</li>
</ul>
<p>You can enable them in your <a href="https://eslint.org/docs/latest/user-guide/configuring" target="_blank" rel="noopener noreferrer">ESLint configuration</a>:</p>
<div class="language-json codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockContent_m3Ux"><pre class="prism-code language-json codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line"><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token property">"plugins"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation">[</span><span class="token string">"@typescript-eslint"</span><span class="token punctuation">]</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token property">"rules"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">    </span><span class="token property">"@typescript-eslint/consistent-type-exports"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">"error"</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">    </span><span class="token property">"@typescript-eslint/consistent-type-imports"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">"error"</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token punctuation">}</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token punctuation">}</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>With those rules enabled, running ESLint on the following code would produce a lint complaint:</p>
<div class="language-ts codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockContent_m3Ux"><pre class="prism-code language-ts codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line"><span class="token keyword">import</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"> GetString </span><span class="token punctuation">}</span><span class="token plain"> </span><span class="token keyword">from</span><span class="token plain"> </span><span class="token string">'./types.js'</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token comment">// All imports in the declaration are only used as types. Use `import type`.</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token keyword">export</span><span class="token plain"> </span><span class="token keyword">function</span><span class="token plain"> </span><span class="token function">getAndLogValue</span><span class="token punctuation">(</span><span class="token plain">getter</span><span class="token operator">:</span><span class="token plain"> GetString</span><span class="token punctuation">)</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token builtin">console</span><span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Value:'</span><span class="token punctuation">,</span><span class="token plain"> </span><span class="token function">getter</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token punctuation">}</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>The two rules can auto-fix code to use <code>type</code>s as necessary when ESLint is run on the command-line with <code>--fix</code> or configured in an editor extension such as the <a href="https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint" target="_blank" rel="noopener noreferrer">VSCode ESLint extension</a>.</p>
<p>For example, the <code>import</code> statement from earlier would be auto-fixed to:</p>
<div class="language-ts codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockContent_m3Ux"><pre class="prism-code language-ts codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line"><span class="token keyword">import</span><span class="token plain"> </span><span class="token keyword">type</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"> GetString </span><span class="token punctuation">}</span><span class="token plain"> </span><span class="token keyword">from</span><span class="token plain"> </span><span class="token string">'./types.js'</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token keyword">export</span><span class="token plain"> </span><span class="token keyword">function</span><span class="token plain"> </span><span class="token function">getAndLogValue</span><span class="token punctuation">(</span><span class="token plain">getter</span><span class="token operator">:</span><span class="token plain"> GetString</span><span class="token punctuation">)</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token builtin">console</span><span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Value:'</span><span class="token punctuation">,</span><span class="token plain"> </span><span class="token function">getter</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token punctuation">}</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<h2 class="anchor anchorWithStickyNavbar_eAos" id="more-lint-rules">More Lint Rules<a href="https://typescript-eslint.io/blog/consistent-type-imports-and-exports-why-and-how#more-lint-rules" class="hash-link" aria-label="Direct link to More Lint Rules" title="Direct link to More Lint Rules">​</a></h2>
<h3 class="anchor anchorWithStickyNavbar_eAos" id="import-plugin-rules"><code>import</code> Plugin Rules<a href="https://typescript-eslint.io/blog/consistent-type-imports-and-exports-why-and-how#import-plugin-rules" class="hash-link" aria-label="Direct link to import-plugin-rules" title="Direct link to import-plugin-rules">​</a></h3>
<p><a href="https://github.com/import-js/eslint-plugin-import" target="_blank" rel="noopener noreferrer"><code>eslint-plugin-import</code></a> is a handy plugin with rules that validate proper imports.
Although some of those rules are made redundant by TypeScript, many are still relevant for TypeScript code.</p>
<p>Two of those rules in particular can be helpful for consistent <code>type</code> imports:</p>
<ul>
<li><a href="https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/consistent-type-specifier-style.md" target="_blank" rel="noopener noreferrer"><code>import/consistent-type-specifier-style</code></a>: enforces consistent use of top-level vs inline <code>type</code> qualifier</li>
<li><a href="https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-duplicates.md#inline-type-imports" target="_blank" rel="noopener noreferrer"><code>import/no-duplicates</code></a>: warns against unnecessary duplicate imports (and with the <code>inline-type-imports</code> option can work in tandem with <code>import/consistent-type-specifier-style</code>).</li>
</ul>
<p>In conjunction with <a href="https://typescript-eslint.io/rules/consistent-type-imports"><code>@typescript-eslint/consistent-type-imports</code></a>, <a href="https://github.com/import-js/eslint-plugin-import" target="_blank" rel="noopener noreferrer"><code>eslint-plugin-import</code></a>'s rules can enforce your imports are always properly qualified and are written in a standard, predictable style (eg always top-level type qualifier or always inline type-qualifier).</p>
<h3 class="anchor anchorWithStickyNavbar_eAos" id="verbatim-module-syntax">Verbatim Module Syntax<a href="https://typescript-eslint.io/blog/consistent-type-imports-and-exports-why-and-how#verbatim-module-syntax" class="hash-link" aria-label="Direct link to Verbatim Module Syntax" title="Direct link to Verbatim Module Syntax">​</a></h3>
<p>TypeScript 5.0 additionally adds a new <a href="https://devblogs.microsoft.com/typescript/announcing-typescript-5-0-beta/#verbatimmodulesyntax" target="_blank" rel="noopener noreferrer"><code>--verbatimModuleSyntax</code></a> compiler option.
<code>verbatimModuleSyntax</code> simplifies TypeScript's logic around whether to preserve imports.
From the TypeScript release notes:</p>
<blockquote>
<p>...any imports or exports without a type modifier are left around.
Anything that uses the type modifier is dropped entirely.</p>
<div class="language-ts codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockContent_m3Ux"><pre class="prism-code language-ts codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line"><span class="token comment">// Erased away entirely.</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token keyword">import</span><span class="token plain"> </span><span class="token keyword">type</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"> </span><span class="token constant">A</span><span class="token plain"> </span><span class="token punctuation">}</span><span class="token plain"> </span><span class="token keyword">from</span><span class="token plain"> </span><span class="token string">'a'</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token comment">// Rewritten to 'import { b } from 'bcd';'</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token keyword">import</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"> b</span><span class="token punctuation">,</span><span class="token plain"> </span><span class="token keyword">type</span><span class="token plain"> </span><span class="token class-name">c</span><span class="token punctuation">,</span><span class="token plain"> </span><span class="token keyword">type</span><span class="token plain"> </span><span class="token class-name">d</span><span class="token plain"> </span><span class="token punctuation">}</span><span class="token plain"> </span><span class="token keyword">from</span><span class="token plain"> </span><span class="token string">'bcd'</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token comment">// Rewritten to 'import {} from 'xyz';'</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token keyword">import</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"> </span><span class="token keyword">type</span><span class="token plain"> </span><span class="token class-name">xyz</span><span class="token plain"> </span><span class="token punctuation">}</span><span class="token plain"> </span><span class="token keyword">from</span><span class="token plain"> </span><span class="token string">'xyz'</span><span class="token punctuation">;</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>With this new option, what you see is what you get.</p>
</blockquote>
<p><code>verbatimModuleSyntax</code> is useful for simplifying transpilation logic around imports - though it does mean that transpiled code such as the may end up with unnecessary import statements.
The <code>import { type xyz } from 'xyz';</code> line from the previous code snippet is an example of this.
For the rare case of needing to import for side effects, leaving in those statements may be desirable - but for most cases you will not want to leave behind an unnecessary side effect import.</p>
<p>typescript-eslint now provides a <a href="https://typescript-eslint.io/rules/no-import-type-side-effects"><code>@typescript-eslint/no-import-type-side-effects</code></a> rule to flag those cases.
If it detects an import that only imports specifiers with inline <code>type</code> qualifiers, it will suggest rewriting the import to use a top-level <code>type</code> qualifier:</p>
<div class="language-diff codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockContent_m3Ux"><pre class="prism-code language-diff codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line"><span class="token deleted-sign deleted prefix deleted">-</span><span class="token deleted-sign deleted line"> import { type A } from 'xyz';</span><br></span><span class="token-line"><span class="token deleted-sign deleted line"></span><span class="token inserted-sign inserted prefix inserted">+</span><span class="token inserted-sign inserted line"> import type { A } from 'xyz';</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<h2 class="anchor anchorWithStickyNavbar_eAos" id="further-reading">Further Reading<a href="https://typescript-eslint.io/blog/consistent-type-imports-and-exports-why-and-how#further-reading" class="hash-link" aria-label="Direct link to Further Reading" title="Direct link to Further Reading">​</a></h2>
<p>You can read more about the rules' configuration options in their docs pages.
See <a href="https://typescript-eslint.io/getting-started">our Getting Started docs</a> for more information on linting your TypeScript code with typescript-eslint.</p>
<h2 class="anchor anchorWithStickyNavbar_eAos" id="supporting-typescript-eslint">Supporting typescript-eslint<a href="https://typescript-eslint.io/blog/consistent-type-imports-and-exports-why-and-how#supporting-typescript-eslint" class="hash-link" aria-label="Direct link to Supporting typescript-eslint" title="Direct link to Supporting typescript-eslint">​</a></h2>
<p>If you enjoyed this blog post and/or use typescript-eslint, please consider <a href="https://opencollective.com/typescript-eslint" target="_blank" rel="noopener noreferrer">supporting us on Open Collective</a>. We're a small volunteer team and could use your support to make the ESLint experience on TypeScript great. Thanks! 💖</p>]]></content:encoded>
            <category>typescript</category>
            <category>imports</category>
            <category>exports</category>
            <category>types</category>
            <category>transpiling</category>
        </item>
        <item>
            <title><![CDATA[ASTs and typescript-eslint]]></title>
            <link>https://typescript-eslint.io/blog/asts-and-typescript-eslint</link>
            <guid>https://typescript-eslint.io/blog/asts-and-typescript-eslint</guid>
            <pubDate>Mon, 05 Dec 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[Describing what an AST (Abstract Syntax Tree) is and why it's useful for ESLint and TypeScript tooling.]]></description>
            <content:encoded><![CDATA[<p>Programmers who work with tools like <a href="https://eslint.org/" target="_blank" rel="noopener noreferrer">ESLint</a> and <a href="https://prettier.io/" target="_blank" rel="noopener noreferrer">Prettier</a> often refer to ASTs.
But what is an AST, why is it useful for these kinds of tools, and how does that interact with ESLint and TypeScript tooling?
Let's dig in!</p>
<h2 class="anchor anchorWithStickyNavbar_eAos" id="whats-an-ast">What's an AST?<a href="https://typescript-eslint.io/blog/asts-and-typescript-eslint#whats-an-ast" class="hash-link" aria-label="Direct link to What's an AST?" title="Direct link to What's an AST?">​</a></h2>
<p><em>Static analysis</em> tools are those that look at code without running it.
They typically <em>parse</em> code, or transform it from a string into a standard format they can reason about known as an <strong>Abstract Syntax Tree</strong> (AST).
ASTs are called such because although they might contain information on the location of constructs within source code, they are an abstract representation that cares more about the semantic structure.</p>
<blockquote>
<p>In other words, an AST is a description of your code's syntax.</p>
</blockquote>
<h3 class="anchor anchorWithStickyNavbar_eAos" id="an-example-ast">An Example AST<a href="https://typescript-eslint.io/blog/asts-and-typescript-eslint#an-example-ast" class="hash-link" aria-label="Direct link to An Example AST" title="Direct link to An Example AST">​</a></h3>
<p>Take this single line of code:</p>
<div class="language-js codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockContent_m3Ux"><pre class="prism-code language-js codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line"><span class="token number">1</span><span class="token plain"> </span><span class="token operator">+</span><span class="token plain"> </span><span class="token number">2</span><span class="token punctuation">;</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>ESLint's AST format, <strong><a href="https://github.com/ESTree/ESTree" target="_blank" rel="noopener noreferrer">ESTree</a></strong>, would describe that line of code as an object like:</p>
<div class="language-json codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockContent_m3Ux"><pre class="prism-code language-json codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line"><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token property">"type"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">"ExpressionStatement"</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token property">"expression"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">    </span><span class="token property">"type"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">"BinaryExpression"</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">    </span><span class="token property">"left"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">      </span><span class="token property">"type"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">"Literal"</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">      </span><span class="token property">"value"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token number">1</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">      </span><span class="token property">"raw"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">"1"</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">    </span><span class="token punctuation">}</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">    </span><span class="token property">"operator"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">"+"</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">    </span><span class="token property">"right"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">      </span><span class="token property">"type"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">"Literal"</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">      </span><span class="token property">"value"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token number">2</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">      </span><span class="token property">"raw"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">"2"</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">    </span><span class="token punctuation">}</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token punctuation">}</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token punctuation">}</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Each piece of code described within an AST description is referred to as a <strong>node</strong>, or AST node.
Each node is given a <strong>node type</strong> indicating the type of code syntax it represents
That code snippet includes four nodes of the following types:</p>
<ul>
<li><em>ExpressionStatement</em>: <code>1 + 2;</code></li>
<li><em>BinaryExpression</em>: <code>1 + 2</code></li>
<li><em>Literal</em>: <code>1</code></li>
<li><em>Literal</em>: <code>2</code></li>
</ul>
<p>That ESTree object representation of the code is what static analysis tools such as <a href="https://eslint.org/" target="_blank" rel="noopener noreferrer">ESLint</a> and <a href="https://prettier.io/" target="_blank" rel="noopener noreferrer">Prettier</a> work with.</p>
<h2 class="anchor anchorWithStickyNavbar_eAos" id="ast-formats">AST Formats<a href="https://typescript-eslint.io/blog/asts-and-typescript-eslint#ast-formats" class="hash-link" aria-label="Direct link to AST Formats" title="Direct link to AST Formats">​</a></h2>
<p>ESTree is more broadly used than just for ESLint -- it is a popular community standard.
ESLint's built-in parser that outputs an ESTree-shaped AST is also a separate package, called <strong><a href="https://github.com/eslint/espree" target="_blank" rel="noopener noreferrer">Espree</a></strong>.</p>
<p>TypeScript has its own separate AST format, often referred to as the TypeScript AST.
Because TypeScript is developed separately and with different goals from ESLint, ESTree, and Espree, its AST also represents nodes differently in many cases.</p>
<ul>
<li>TS's AST is optimized for its use case of parsing incomplete code and typechecking.</li>
<li>ESTree is unoptimized and intended for "general purpose" use-cases of traversing the AST.</li>
</ul>
<p>ESLint rules are by default only given nodes in the ESTree AST format - which has no knowledge of TypeScript-specific syntax such as interfaces.
On the other hand, TypeScript's type checking APIs require nodes in the TypeScript AST format.</p>
<h3 class="anchor anchorWithStickyNavbar_eAos" id="enter-tsestree">Enter TSESTree<a href="https://typescript-eslint.io/blog/asts-and-typescript-eslint#enter-tsestree" class="hash-link" aria-label="Direct link to Enter TSESTree" title="Direct link to Enter TSESTree">​</a></h3>
<p>To resolve the incompatibilities between ESTrees and the TypeScript AST typescript-eslint provides its own <a href="https://typescript-eslint.io/packages/parser" target="_blank" rel="noopener noreferrer"><code>@typescript-eslint/parser</code> package</a> which:</p>
<ol>
<li>First parses TypeScript syntax into a TypeScript AST</li>
<li>Creates an ESTree AST based on that TypeScript AST</li>
<li>Keeps track of equivalent nodes across each AST</li>
</ol>
<p>By creating both an ESTree AST and a TypeScript AST, the typescript-eslint parser allows ESLint rules to work with TypeScript code.
That's why the <a href="https://typescript-eslint.io/getting-started" target="_blank" rel="noopener noreferrer">Getting Started guide</a> for typescript-eslint has you specify <code>parser: '@typescript-eslint/parser'</code> in your ESLint config!</p>
<p>We commonly refer to the ESTree format that also includes TypeScript-specific syntax as <strong>TSESTree</strong>.</p>
<h3 class="anchor anchorWithStickyNavbar_eAos" id="ast-playground">AST Playground<a href="https://typescript-eslint.io/blog/asts-and-typescript-eslint#ast-playground" class="hash-link" aria-label="Direct link to AST Playground" title="Direct link to AST Playground">​</a></h3>
<p>The <a href="https://typescript-eslint.io/play#showAST=es" target="_blank" rel="noopener noreferrer">typescript-eslint playground</a> contains an AST explorer that generates an interactive AST for any code entered into the playground.
You can activate it under <em>Options</em> &gt; <em>AST Explorer</em> on its left sidebar by selecting the value of <em>AST Viewer</em>.</p>
<h2 class="anchor anchorWithStickyNavbar_eAos" id="further-resources">Further Resources<a href="https://typescript-eslint.io/blog/asts-and-typescript-eslint#further-resources" class="hash-link" aria-label="Direct link to Further Resources" title="Direct link to Further Resources">​</a></h2>
<p>You can play more with various other ASTs on <a href="https://astexplorer.net/" target="_blank" rel="noopener noreferrer">astexplorer.net</a>, including those for other languages such as CSS and HTML.</p>
<p>The <a href="https://en.wikipedia.org/wiki/Abstract_syntax_tree" target="_blank" rel="noopener noreferrer">AST Wikipedia article</a> has a great deal more context and history on ASTs.</p>
<h3 class="anchor anchorWithStickyNavbar_eAos" id="glossary">Glossary<a href="https://typescript-eslint.io/blog/asts-and-typescript-eslint#glossary" class="hash-link" aria-label="Direct link to Glossary" title="Direct link to Glossary">​</a></h3>
<p>Putting together all the terms introduces in this article:</p>
<ul>
<li><strong>AST (Abstract Syntax Tree)</strong>: An object representation of your code's syntax.</li>
<li><strong>Espree</strong>: ESLint's built-in parser that outputs an ESTree-shaped AST.</li>
<li><strong>ESTree</strong>: The AST specification used by ESLint and other common JavaScript tools.</li>
<li><strong>Node Type</strong>: What kind of code syntax an AST node refers to, such as <em>BinaryExpression</em> or <em>Literal</em>.</li>
<li><strong>Node</strong>: A single range of code syntax in an AST.</li>
<li><strong>Parser</strong>: A tool that reads in a string and outputs an AST.</li>
<li><strong>TSESTree</strong>: Our extension to the ESTree AST format that also includes TypeScript-specific syntax.</li>
</ul>
<h3 class="anchor anchorWithStickyNavbar_eAos" id="typescript-lint-rules-and-asts">TypeScript Lint Rules and ASTs<a href="https://typescript-eslint.io/blog/asts-and-typescript-eslint#typescript-lint-rules-and-asts" class="hash-link" aria-label="Direct link to TypeScript Lint Rules and ASTs" title="Direct link to TypeScript Lint Rules and ASTs">​</a></h3>
<p>Interested in how these ASTs work with ESLint rules?
We collaborated with our friends at Sourcegraph on a <a href="https://sourcegraph.com/notebooks/Tm90ZWJvb2s6MTA2OA==" target="_blank" rel="noopener noreferrer">Tour de Source on typescript-eslint</a>.
Read on to learn how ESLint rules use ASTs to analyze code files and, thanks to <code>@typescript-eslint/parser</code>, call TypeScript's type checking APIs to analyze code.</p>
<h2 class="anchor anchorWithStickyNavbar_eAos" id="supporting-typescript-eslint">Supporting typescript-eslint<a href="https://typescript-eslint.io/blog/asts-and-typescript-eslint#supporting-typescript-eslint" class="hash-link" aria-label="Direct link to Supporting typescript-eslint" title="Direct link to Supporting typescript-eslint">​</a></h2>
<p>If you enjoyed this blog post and/or use typescript-eslint, please consider <a href="https://opencollective.com/typescript-eslint" target="_blank" rel="noopener noreferrer">supporting us on Open Collective</a>. We're a small volunteer team and could use your support to make the ESLint experience on TypeScript great. Thanks! 💖</p>]]></content:encoded>
            <category>ast</category>
            <category>abstract syntax tree</category>
            <category>parser</category>
            <category>parsing</category>
            <category>prettier</category>
        </item>
        <item>
            <title><![CDATA[Automated Rule Docs With Docusaurus and Remark]]></title>
            <link>https://typescript-eslint.io/blog/automated-rule-docs-with-docusaurus-and-remark</link>
            <guid>https://typescript-eslint.io/blog/automated-rule-docs-with-docusaurus-and-remark</guid>
            <pubDate>Sun, 18 Sep 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[How typescript-eslint generates much of the docs pages for each of its lint rules.]]></description>
            <content:encoded><![CDATA[<p>The typescript-eslint website at <a href="https://typescript-eslint.io/" target="_blank" rel="noopener noreferrer">https://typescript-eslint.io</a> is the canonical location for documentation on how to use ESLint on TypeScript code.
The site includes a documentation page for each of the over 100 ESLint rules exposed by its ESLint plugin.
Each of those rule docs pages includes a description of the rule, any options it allows, links to its source code, and other important information about its usage.</p>
<p>Until recently, keeping descriptions of rules consistent between their source code and docs pages was a cumbersome manual chore.
We'd written a suite of Jest tests to verify they matched -- but those tests didn't capture everything, often failed with cryptic messages, and were missed by less experienced contributors.</p>
<p>We're happy to say that now, we've overhauled rule docs pages to automatically generate metadata information from rule source code.
That means the pages always display up-to-date information without developers needing to manually rewrite docs on rule changes.
Hooray! 🎉</p>
<p>This blog post gives an overview of the <a href="https://github.com/typescript-eslint/typescript-eslint/pull/5386" target="_blank" rel="noopener noreferrer">chore to generate rule docs options automatically</a>.</p>
<h2 class="anchor anchorWithStickyNavbar_eAos" id="tools-in-play">Tools in Play<a href="https://typescript-eslint.io/blog/automated-rule-docs-with-docusaurus-and-remark#tools-in-play" class="hash-link" aria-label="Direct link to Tools in Play" title="Direct link to Tools in Play">​</a></h2>
<p><a href="https://typescript-eslint.io/" target="_blank" rel="noopener noreferrer">https://typescript-eslint.io</a> is built on <a href="https://docusaurus.io/" target="_blank" rel="noopener noreferrer">Docusaurus</a>, a powerful static site generator tailored to documentation websites and blogs.
Docusaurus comes with sensible defaults, extensive configuration options, and thoroughly fleshed out documentation.
We're big fans.
❤️</p>
<p><a href="https://docusaurus.io/docs/blog" target="_blank" rel="noopener noreferrer">Docusaurus blogs</a> support writing blog posts in <a href="https://mdxjs.com/" target="_blank" rel="noopener noreferrer">MDX</a>, a rich superset of Markdown that allows inserting JSX components.
Docusaurus supports MDX using <a href="https://remark.js.org/" target="_blank" rel="noopener noreferrer">remark</a>, a Markdown processor powered by plugins.
Remark plugins take in Markdown files in a format known as an Abstract Syntax Tree (or AST), and output modified versions of those ASTs.</p>
<p>You can see what Remark's AST equivalent of a Markdown document looks like by visiting <a href="https://astexplorer.net/" target="_blank" rel="noopener noreferrer">AST Explorer</a> and selecting the Markdown language.</p>
<figure><p><img decoding="async" loading="lazy" alt="A screenshot of the astexplorer.net interface. The left pane shows a snippet of Markdown source with one paragraph highlighted. The right pane shows its AST structure in a collapsible JSON format, with the paragraph&amp;#39;s corresponding AST node automatically highlighted." src="https://typescript-eslint.io/assets/images/ast-explorer-remark-3c6fd8bff356b5b2db817e33023ae87e.png" width="2940" height="1668" class="img_veEs"></p><figcaption><em></em><p><em>astexplorer.net showing the default snippet with the paragraph highlighted</em></p></figcaption></figure>
<p>Lastly, Remark and several other packages around parsing and modifying ASTs are built on the <a href="https://github.com/unifiedjs/unified" target="_blank" rel="noopener noreferrer"><code>unified</code> project</a>.
The unified AST format adheres to the <a href="https://github.com/syntax-tree/unist" target="_blank" rel="noopener noreferrer"><code>unist</code> specification</a>.</p>
<h3 class="anchor anchorWithStickyNavbar_eAos" id="custom-remark-plugins">Custom Remark Plugins<a href="https://typescript-eslint.io/blog/automated-rule-docs-with-docusaurus-and-remark#custom-remark-plugins" class="hash-link" aria-label="Direct link to Custom Remark Plugins" title="Direct link to Custom Remark Plugins">​</a></h3>
<p>Remark allows projects to register any number of custom Remark plugins for transforming Markdown contents.
For example, typescript-eslint.io already uses <a href="https://www.npmjs.com/package/remark-docusaurus-tabs" target="_blank" rel="noopener noreferrer"><code>remark-docusaurus-tabs</code></a>.</p>
<p>The relevant parts of <a href="https://github.com/typescript-eslint/typescript-eslint/blob/39829c01906f326fec94e9b3a5fdb1730eb02002/packages/website/docusaurusConfig.ts" target="_blank" rel="noopener noreferrer">typescript-eslint.io's Docusaurus config</a> specify the <code>remark-docusaurus-tabs</code> plugin and the custom <code>./plugins/generated-rule-docs</code> plugin:</p>
<div class="language-ts codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockContent_m3Ux"><pre class="prism-code language-ts codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line"><span class="token keyword">import</span><span class="token plain"> tabsPlugin </span><span class="token keyword">from</span><span class="token plain"> </span><span class="token string">'remark-docusaurus-tabs'</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token keyword">import</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"> generatedRuleDocs </span><span class="token punctuation">}</span><span class="token plain"> </span><span class="token keyword">from</span><span class="token plain"> </span><span class="token string">'./plugins/generated-rule-docs'</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token keyword">export</span><span class="token plain"> </span><span class="token operator">=</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  presets</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation">[</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">    </span><span class="token punctuation">[</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">      </span><span class="token string">'classic'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">      </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">        beforeDefaultRemarkPlugins</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation">[</span><span class="token plain">tabsPlugin</span><span class="token punctuation">,</span><span class="token plain"> generatedRuleDocs</span><span class="token punctuation">]</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">      </span><span class="token punctuation">}</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">    </span><span class="token punctuation">]</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token punctuation">]</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token punctuation">}</span><span class="token punctuation">;</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Those plugins are specified inside the <a href="https://docusaurus.io/docs/api/plugins/@docusaurus/plugin-content-blog#beforeDefaultRemarkPlugins" target="_blank" rel="noopener noreferrer"><code>beforeDefaultRemarkPlugins</code></a> option, so they run before the Docusaurus internal Remark plugin generates the tables of contents for the docs pages. This allows the headings that our custom plugin inserts to be present in the table of contents.</p>
<h2 class="anchor anchorWithStickyNavbar_eAos" id="automated-changes">Automated Changes<a href="https://typescript-eslint.io/blog/automated-rule-docs-with-docusaurus-and-remark#automated-changes" class="hash-link" aria-label="Direct link to Automated Changes" title="Direct link to Automated Changes">​</a></h2>
<p>The typescript-eslint.io website's documentation contents are all stored as <code>.md</code>, or Markdown files.
Most of those <code>.md</code> files correspond to a lint rule under the same name.
The <a href="https://typescript-eslint.io/rules/no-for-in-array" target="_blank" rel="noopener noreferrer"><code>@typescript-eslint/no-for-in-array</code> rule</a>, for example, is documented in the <a href="https://github.com/typescript-eslint/typescript-eslint/blob/39829c01906f326fec94e9b3a5fdb1730eb02002/packages/eslint-plugin/docs/rules/no-for-in-array.md" target="_blank" rel="noopener noreferrer"><code>no-for-in-array.md</code> file</a>.</p>
<p>Our Remark plugin:</p>
<ol>
<li>Takes in the AST and metadata of a documentation file</li>
<li>Tries to find the corresponding typescript-eslint rule for the file's name</li>
<li>If one was found, applies a set of modifications to the AST</li>
</ol>
<p>The rest of this section of the blog post will give a high-level overview of what kinds of AST modifications take place.
You can dive into <a href="https://github.com/typescript-eslint/typescript-eslint/blob/39829c01906f326fec94e9b3a5fdb1730eb02002/packages/website/plugins/generated-rule-docs.ts" target="_blank" rel="noopener noreferrer">the source code of our plugin</a> for more details if you're curious.</p>
<h3 class="anchor anchorWithStickyNavbar_eAos" id="matching-docs-to-rules">Matching Docs to Rules<a href="https://typescript-eslint.io/blog/automated-rule-docs-with-docusaurus-and-remark#matching-docs-to-rules" class="hash-link" aria-label="Direct link to Matching Docs to Rules" title="Direct link to Matching Docs to Rules">​</a></h3>
<p>The <a href="https://www.npmjs.com/package/@typescript-eslint/eslint-plugin" target="_blank" rel="noopener noreferrer"><code>@typescript-eslint/eslint-plugin</code> package</a> exports an object with a <code>rules</code> property containing all the typescript-eslint lint rules.
Properties have names like <code>"array-type"</code> that map to the rule object exported by files like <a href="https://github.com/typescript-eslint/typescript-eslint/blob/39829c01906f326fec94e9b3a5fdb1730eb02002/packages/eslint-plugin/src/rules/array-type.ts#L86" target="_blank" rel="noopener noreferrer"><code>array-type.ts</code></a>.</p>
<p>Remark plugins are able to access the name of the file they're modifying by accessing <code>file.stem</code>, as in the following code snippet.
Names of rule docs files can then be matched up with rules exported by the ESLint plugin object.
Docs files that don't correspond to a rule don't have any AST modifications done in this plugin:</p>
<div class="language-ts codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockContent_m3Ux"><pre class="prism-code language-ts codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line"><span class="token keyword">import</span><span class="token plain"> </span><span class="token operator">*</span><span class="token plain"> </span><span class="token keyword">as</span><span class="token plain"> eslintPlugin </span><span class="token keyword">from</span><span class="token plain"> </span><span class="token string">'@typescript-eslint/eslint-plugin'</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token keyword">import</span><span class="token plain"> </span><span class="token keyword">type</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"> Plugin </span><span class="token punctuation">}</span><span class="token plain"> </span><span class="token keyword">from</span><span class="token plain"> </span><span class="token string">'unified'</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token keyword">export</span><span class="token plain"> </span><span class="token keyword">const</span><span class="token plain"> generatedRuleDocs</span><span class="token operator">:</span><span class="token plain"> </span><span class="token function-variable function">Plugin</span><span class="token plain"> </span><span class="token operator">=</span><span class="token plain"> </span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token plain"> </span><span class="token operator">=&gt;</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token keyword">return</span><span class="token plain"> </span><span class="token keyword">async</span><span class="token plain"> </span><span class="token punctuation">(</span><span class="token plain">root</span><span class="token punctuation">,</span><span class="token plain"> file</span><span class="token punctuation">)</span><span class="token plain"> </span><span class="token operator">=&gt;</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">    </span><span class="token keyword">if</span><span class="token plain"> </span><span class="token punctuation">(</span><span class="token plain">file</span><span class="token punctuation">.</span><span class="token plain">stem </span><span class="token operator">==</span><span class="token plain"> </span><span class="token keyword">null</span><span class="token punctuation">)</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">      </span><span class="token keyword">return</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">    </span><span class="token punctuation">}</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line"><span class="token plain">    </span><span class="token keyword">const</span><span class="token plain"> rule </span><span class="token operator">=</span><span class="token plain"> eslintPlugin</span><span class="token punctuation">.</span><span class="token plain">rules</span><span class="token punctuation">[</span><span class="token plain">file</span><span class="token punctuation">.</span><span class="token plain">stem</span><span class="token punctuation">]</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">    </span><span class="token keyword">const</span><span class="token plain"> meta </span><span class="token operator">=</span><span class="token plain"> rule</span><span class="token operator">?.</span><span class="token plain">meta</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">    </span><span class="token keyword">if</span><span class="token plain"> </span><span class="token punctuation">(</span><span class="token operator">!</span><span class="token plain">meta</span><span class="token operator">?.</span><span class="token plain">docs</span><span class="token punctuation">)</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">      </span><span class="token keyword">return</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">    </span><span class="token punctuation">}</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line"><span class="token plain">    </span><span class="token comment">// ... (rest of the plugin here!) ...</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token punctuation">}</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token punctuation">}</span><span class="token punctuation">;</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<h3 class="anchor anchorWithStickyNavbar_eAos" id="removing-an-ast-node">Removing an AST Node<a href="https://typescript-eslint.io/blog/automated-rule-docs-with-docusaurus-and-remark#removing-an-ast-node" class="hash-link" aria-label="Direct link to Removing an AST Node" title="Direct link to Removing an AST Node">​</a></h3>
<p>The first AST modification our plugin does is to remove a node that exists in <code>.md</code> docs files but doesn't need to exist in the typescript-eslint.io website.
The <code>.md</code> source files start with a callout to let people know to go to the website:</p>
<div class="language-md codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockContent_m3Ux"><pre class="prism-code language-md codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line"><span class="token blockquote punctuation">&gt;</span><span class="token plain"> 🛑 This file is source code, not the primary documentation location! 🛑</span><br></span><span class="token-line"><span class="token plain"></span><span class="token blockquote punctuation">&gt;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token blockquote punctuation">&gt;</span><span class="token plain"> See </span><span class="token bold punctuation">**</span><span class="token bold content">https://typescript-eslint.io/rules/adjacent-overload-signatures</span><span class="token bold punctuation">**</span><span class="token plain"> for documentation.</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>That blockquote and other root-level nodes are stored as an array under the <code>children</code> property of the AST root node:</p>
<div class="language-ts codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockContent_m3Ux"><pre class="prism-code language-ts codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line"><span class="token plain">root</span><span class="token punctuation">.</span><span class="token plain">children</span><span class="token punctuation">.</span><span class="token function">splice</span><span class="token punctuation">(</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  root</span><span class="token punctuation">.</span><span class="token plain">children</span><span class="token punctuation">.</span><span class="token function">findIndex</span><span class="token punctuation">(</span><span class="token plain">v </span><span class="token operator">=&gt;</span><span class="token plain"> v</span><span class="token punctuation">.</span><span class="token plain">type </span><span class="token operator">===</span><span class="token plain"> </span><span class="token string">'blockquote'</span><span class="token punctuation">)</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token number">1</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token punctuation">)</span><span class="token punctuation">;</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<div class="theme-admonition theme-admonition-info admonition_pzuZ alert alert--info"><div class="admonitionHeading_uJho"><span class="admonitionIcon_vMH2"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>Historical context</div><div class="admonitionContent_gazR"><p>Before typescript-eslint.io existed, the canonical documentation URL for typescript-eslint's lint rules was the GitHub link to their corresponding <code>.md</code> file.
Now that we have a rich documentation site and have automated much of what used to be in those <code>.md</code> files, they're no longer a good place to look for documentation.</p></div></div>
<h3 class="anchor anchorWithStickyNavbar_eAos" id="adding-an-ast-node">Adding an AST Node<a href="https://typescript-eslint.io/blog/automated-rule-docs-with-docusaurus-and-remark#adding-an-ast-node" class="hash-link" aria-label="Direct link to Adding an AST Node" title="Direct link to Adding an AST Node">​</a></h3>
<p>Most of the modifications in our plugin are to add more nodes to the AST.
The rule's <code>meta.docs</code> property contains a plethora of information about the rule.</p>
<p>For example, <code>meta.docs.description</code> is a plain-text description of what the rule does.
We add a blockquote containing the rule's description as text.
Inline code (text surrounded by <code>`</code> backticks) is rendered as a Markdown <code>inlineCode</code> node:</p>
<div class="language-ts codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockContent_m3Ux"><pre class="prism-code language-ts codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line"><span class="token plain">root</span><span class="token punctuation">.</span><span class="token plain">children</span><span class="token punctuation">.</span><span class="token function">unshift</span><span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  children</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation">[</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">    </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">      children</span><span class="token operator">:</span><span class="token plain"> meta</span><span class="token punctuation">.</span><span class="token plain">docs</span><span class="token punctuation">.</span><span class="token plain">description</span><br></span><span class="token-line"><span class="token plain">        </span><span class="token punctuation">.</span><span class="token function">split</span><span class="token punctuation">(</span><span class="token regex regex-delimiter">/</span><span class="token regex regex-source language-regex">`</span><span class="token regex regex-source language-regex group punctuation">(</span><span class="token regex regex-source language-regex char-set class-name">.</span><span class="token regex regex-source language-regex quantifier number">+?</span><span class="token regex regex-source language-regex group punctuation">)</span><span class="token regex regex-source language-regex">`</span><span class="token regex regex-delimiter">/</span><span class="token punctuation">)</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">        </span><span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token plain">value</span><span class="token punctuation">,</span><span class="token plain"> index</span><span class="token punctuation">,</span><span class="token plain"> array</span><span class="token punctuation">)</span><span class="token plain"> </span><span class="token operator">=&gt;</span><span class="token plain"> </span><span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">          type</span><span class="token operator">:</span><span class="token plain"> index </span><span class="token operator">%</span><span class="token plain"> </span><span class="token number">2</span><span class="token plain"> </span><span class="token operator">===</span><span class="token plain"> </span><span class="token number">0</span><span class="token plain"> </span><span class="token operator">?</span><span class="token plain"> </span><span class="token string">'text'</span><span class="token plain"> </span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'inlineCode'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">          value</span><span class="token operator">:</span><span class="token plain"> index </span><span class="token operator">===</span><span class="token plain"> array</span><span class="token punctuation">.</span><span class="token plain">length </span><span class="token operator">-</span><span class="token plain"> </span><span class="token number">1</span><span class="token plain"> </span><span class="token operator">?</span><span class="token plain"> </span><span class="token template-string template-punctuation string">`</span><span class="token template-string interpolation interpolation-punctuation punctuation">${</span><span class="token template-string interpolation">value</span><span class="token template-string interpolation interpolation-punctuation punctuation">}</span><span class="token template-string string">.</span><span class="token template-string template-punctuation string">`</span><span class="token plain"> </span><span class="token operator">:</span><span class="token plain"> value</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">        </span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">      type</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'paragraph'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">    </span><span class="token punctuation">}</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token punctuation">]</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  type</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'blockquote'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>For example, <a href="https://typescript-eslint.io/rules/array-type" target="_blank" rel="noopener noreferrer">typescript-eslint.io/rules/array-type</a> has the equivalent of this blockquote added now:</p>
<div class="language-md codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockContent_m3Ux"><pre class="prism-code language-md codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line"><span class="token blockquote punctuation">&gt;</span><span class="token plain"> Require using either </span><span class="token code-snippet code keyword">`T[]`</span><span class="token plain"> or </span><span class="token code-snippet code keyword">`Array&lt;T&gt;`</span><span class="token plain"> for arrays.</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Quite a few other modifications to the AST involve adding AST nodes that are expected to exist on the page.
It ensures expected headings such as <em><code>## How to Use</code></em> and <em><code>## Options</code></em> exist, inserting them if not.</p>
<h3 class="anchor anchorWithStickyNavbar_eAos" id="adding-a-jsx-ast-node">Adding a JSX AST Node<a href="https://typescript-eslint.io/blog/automated-rule-docs-with-docusaurus-and-remark#adding-a-jsx-ast-node" class="hash-link" aria-label="Direct link to Adding a JSX AST Node" title="Direct link to Adding a JSX AST Node">​</a></h3>
<p>Remember when the concept of MDX files including JSX tags was mentioned earlier in this blog post, and then never referenced again?
We did end up injecting one React component as a JSX tag in the plugin.</p>
<p>In our <a href="https://github.com/typescript-eslint/typescript-eslint/blob/39829c01906f326fec94e9b3a5fdb1730eb02002/packages/website/src/theme/MDXComponents/index.tsx#L2" target="_blank" rel="noopener noreferrer">MDX component configuration</a>, <code>'rule-attributes'</code> maps to a <a href="https://github.com/typescript-eslint/typescript-eslint/blob/39829c01906f326fec94e9b3a5fdb1730eb02002/packages/website/src/theme/MDXComponents/RuleAttributes.tsx#L7" target="_blank" rel="noopener noreferrer"><code>RulesAttribute</code> React component</a> that renders a list of rule metadata.
That list is a little too complex to easily render directly in Markdown.</p>
<p>MDX builds on Remark and additionally supports nodes of type <code>'jsx'</code> that include raw JSX syntax:</p>
<div class="language-ts codeBlockContainer_CoL1 theme-code-block"><div class="codeBlockContent_m3Ux"><pre class="prism-code language-ts codeBlock_qGQc thin-scrollbar" tabindex="0"><code class="codeBlockLines_p187"><span class="token-line"><span class="token keyword">const</span><span class="token plain"> attributesH2Index </span><span class="token operator">=</span><span class="token plain"> root</span><span class="token punctuation">.</span><span class="token plain">children</span><span class="token punctuation">.</span><span class="token function">findIndex</span><span class="token punctuation">(</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  child </span><span class="token operator">=&gt;</span><span class="token plain"> </span><span class="token function">nodeIsHeading</span><span class="token punctuation">(</span><span class="token plain">child</span><span class="token punctuation">)</span><span class="token plain"> </span><span class="token operator">&amp;&amp;</span><span class="token plain"> child</span><span class="token punctuation">.</span><span class="token plain">depth </span><span class="token operator">===</span><span class="token plain"> </span><span class="token number">2</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line"><span class="token plain">root</span><span class="token punctuation">.</span><span class="token plain">children</span><span class="token punctuation">.</span><span class="token function">splice</span><span class="token punctuation">(</span><span class="token plain">attributesH2Index</span><span class="token punctuation">,</span><span class="token plain"> </span><span class="token number">0</span><span class="token punctuation">,</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  type</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">'jsx'</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  value</span><span class="token operator">:</span><span class="token plain"> </span><span class="token template-string template-punctuation string">`</span><span class="token template-string string">&lt;rule-attributes name="</span><span class="token template-string interpolation interpolation-punctuation punctuation">${</span><span class="token template-string interpolation">file</span><span class="token template-string interpolation punctuation">.</span><span class="token template-string interpolation">stem</span><span class="token template-string interpolation interpolation-punctuation punctuation">}</span><span class="token template-string string">" /&gt;</span><span class="token template-string template-punctuation string">`</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token keyword">function</span><span class="token plain"> </span><span class="token function">nodeIsHeading</span><span class="token punctuation">(</span><span class="token plain">node</span><span class="token operator">:</span><span class="token plain"> unist</span><span class="token punctuation">.</span><span class="token plain">Node</span><span class="token punctuation">)</span><span class="token operator">:</span><span class="token plain"> node </span><span class="token keyword">is</span><span class="token plain"> mdast</span><span class="token punctuation">.</span><span class="token plain">Heading </span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain">  </span><span class="token keyword">return</span><span class="token plain"> node</span><span class="token punctuation">.</span><span class="token plain">type </span><span class="token operator">===</span><span class="token plain"> </span><span class="token string">'heading'</span><span class="token punctuation">;</span><span class="token plain"></span><br></span><span class="token-line"><span class="token plain"></span><span class="token punctuation">}</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_BmR_" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_Nw83"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_YsmE"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<h2 class="anchor anchorWithStickyNavbar_eAos" id="whats-next">What's Next<a href="https://typescript-eslint.io/blog/automated-rule-docs-with-docusaurus-and-remark#whats-next" class="hash-link" aria-label="Direct link to What's Next" title="Direct link to What's Next">​</a></h2>
<p>We're relieved that we no longer have to manually update scores of documentation on every code change.
This plugin's automation frees up our documentation time to focus on improving the contents of the pages themselves.
You can query our <a href="https://github.com/typescript-eslint/typescript-eslint/issues" target="_blank" rel="noopener noreferrer">issue tracker</a> for <a href="https://github.com/typescript-eslint/typescript-eslint/issues?q=is%3Aopen+is%3Aissue+label%3Adocumentation" target="_blank" rel="noopener noreferrer">issues with the <code>documentation</code> label</a> to see what's coming up next.
I'm excited to focus in particular on <a href="https://github.com/typescript-eslint/typescript-eslint/issues/4861" target="_blank" rel="noopener noreferrer">Docs: Proofread rule docs for clarity (#4861)</a>.</p>
<h2 class="anchor anchorWithStickyNavbar_eAos" id="appreciation-and-thanks">Appreciation and Thanks<a href="https://typescript-eslint.io/blog/automated-rule-docs-with-docusaurus-and-remark#appreciation-and-thanks" class="hash-link" aria-label="Direct link to Appreciation and Thanks" title="Direct link to Appreciation and Thanks">​</a></h2>
<p>We'd like to extend thanks to <a href="https://github.com/Josh-Cena" target="_blank" rel="noopener noreferrer">Joshua Chen</a>, one of the Docusaurus maintainers who also has been helping us with Docusaurus — and helped proofread <a href="https://github.com/typescript-eslint/typescript-eslint/pull/5593" target="_blank" rel="noopener noreferrer">this blog post's PR</a>.
Without Joshua, this change would have taken us a great deal longer (if we'd have been able to tackle it at all).
Thanks Joshua! 🤗</p>
<h2 class="anchor anchorWithStickyNavbar_eAos" id="supporting-typescript-eslint">Supporting typescript-eslint<a href="https://typescript-eslint.io/blog/automated-rule-docs-with-docusaurus-and-remark#supporting-typescript-eslint" class="hash-link" aria-label="Direct link to Supporting typescript-eslint" title="Direct link to Supporting typescript-eslint">​</a></h2>
<p>If you enjoyed this blog post and/or use typescript-eslint, please consider <a href="https://opencollective.com/typescript-eslint" target="_blank" rel="noopener noreferrer">supporting us on Open Collective</a>. We're a small volunteer team and could use your support to make the ESLint experience on TypeScript great. Thanks! 💖</p>]]></content:encoded>
            <category>documentation</category>
            <category>docusaurus</category>
            <category>remark</category>
        </item>
    </channel>
</rss>