添加链接
注册
登录
link管理
链接快照平台
输入网页链接,自动生成快照
标签化管理网页链接
相关文章推荐
耍酷的炒饭
·
在@Scheduled( .yml ...
·
1 月前
·
近视的茶壶
·
如何使用Pandas ...
·
2 月前
·
快乐的剪刀
·
Adobe Photoshop ...
·
2 月前
·
卖萌的伏特加
·
装配式建筑网
·
4 月前
·
火星上的羽毛球
·
海南反季节瓜菜安全链缘何断裂
·
1 年前
·
link管理
›
tsconfig strictness | Learn TypeScript w/ Mike North
https://www.typescript-training.com/course/enterprise-v2/03-tsconfig-strictness/
聪明伶俐的蛋挞
5 月前
</noscript><div id="___gatsby"><div style="outline:none" tabindex="-1" id="gatsby-focus-wrapper"><div style="margin-left:auto;margin-right:auto;max-width:52.5rem;padding:2.625rem 1.3125rem"><header><h3 style="margin-top:0"><a style="box-shadow:none;color:inherit" href="/">Learn TypeScript w/ Mike North</a></h3></header><main><article class="blog-post"><header><a style="margin-top:1.75rem;margin-bottom:0" rel="next" class="course-title-link" href="/course/enterprise-v2"><span class="course-title">Enterprise-Scale TypeScript v2</span></a><a href="https://github.com/mike-north/ts-fundamentals-v3/edit/main/packages/website/content/blog/enterprise-v2/03-tsconfig-strictness/index.md" rel="noopener noreferrer" target="_blank"><div class="edit-on-github-link"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAACLElEQVR4AbSWA6weQRSFf9W2FTaubcVWbUW1FaMO6zao3agIa0S1bdt+Z5Lzksnm3lnNv8n3MPfcc+56M1G3enXq1gZjwBZwCXwG/8lnrm2hpnbG1waz1mAn+M2wKPxmT+s0wdXAevCPpkn4R49qSfb6Hk18cA+0jhreB3z0Fk7o2ScsvK3PcGWItlp4DXA/0HAN7E041Ef2XrPXmVFDGmCTYDKUtXK8vV4EbrtjxL4tX1Bbjr1DBd9NwfB2yl60Ee6MliAn7ECOtWqB9TaKdztbtE8RtffwHGmveO8rFdQHfxTRCA8DjJC8mVnfCCYogsegpocBaoJHSsYEI9ipFEd7fJyPVjJ2muI15fBU8zhANeU0XzPFb0LhYcbzZjyFnG8Z5dDcLsIAd6QsbYBPRRjgk5SlFkBdj+F11R3FjwtKcbjHAYYrGRdMcaNSvAgKHsIL9JIyNhrBIKlIVnoYYKXDf5ARVAFfHaLdoH6C4AbsFX2ZWaVUvNoqLAE9wXFr7RfYBcaBdiCvHOrOYCLYx57/DlbbzU3Bd+tDcjooB84JjftAVhggCw5Q44RZTYMGiwKiTqCF8CLp5jjsPSIOsEi7Wk9aoiNcrw7GgHlgAMg7BqgTFs6MgmZQP/DInBzzwqvuCqd3/TCTZuC21XQCzAQjwRxQPskA9GwW5yPikGJUPcEAh2J/3PCqHgtepRjgNW/dbJonWWXelrfAG1DOoS1HjdHOAJUzJRvsAADCkEdhn2JIcgAAAABJRU5ErkJggg==" alt="GitHub"/>Edit on GitHub</div></a><h1 class="post-title">tsconfig strictness</h1><p style="font-size:0.83255rem;line-height:1.75rem;display:block;margin-bottom:1.75rem">October 27, 2023</p></header><nav><ul style="display:flex;flex-wrap:wrap;justify-content:space-between;list-style:none;padding:0"><li><a rel="prev" href="/course/enterprise-v2/02-ts-library-zero-to-one/">← <!-- -->TypeScript Libraries - Zero to One</a></li><li><a rel="next" href="/course/enterprise-v2/04-app-vs-library-concerns/">App vs Library Concerns<!-- --> →</a></li></ul></nav><div class="post-toc"><div class="post-toc__title">Table of Contents</div><section class="post-toc__content"><ul> <li><a href="#whats-in-the-tsconfigjson">What’s in the <code>tsconfig.json</code>?</a></li> <p><a href="#in-my-tsconfigjson-what-exactly-is-strict">In my <code>tsconfig.json</code> what exactly is “strict”?</a></p> <li><a href="#noimplicitany"><code>noImplicitAny</code></a></li> <li><a href="#noimplicitthis"><code>noImplicitThis</code></a></li> <li><a href="#alwaysstrict"><code>alwaysStrict</code></a></li> <li><a href="#strictbindcallapply"><code>strictBindCallApply</code></a></li> <li><a href="#strictnullchecks"><code>strictNullChecks</code></a></li> <li><a href="#strictfunctiontypes"><code>strictFunctionTypes</code></a></li> <li><a href="#strictpropertyinitialization"><code>strictPropertyInitialization</code></a></li> <p><a href="#even-more-strict">Even more strict</a></p> <li><a href="#nounusedlocals"><code>noUnusedLocals</code></a></li> <li><a href="#nounusedparameters"><code>noUnusedParameters</code></a></li> <li><a href="#noimplicitreturns"><code>noImplicitReturns</code></a></li> <li><a href="#nofallthroughcasesinswitch"><code>noFallthroughCasesInSwitch</code></a></li> <li><a href="#types"><code>types</code></a></li> <li><a href="#stripinternal-most-important-for-libraries"><code>stripInternal</code> (most important for libraries)</a></li> <li><a href="#exactoptionalpropertytypes"><code>exactOptionalPropertyTypes</code></a></li> <li><a href="#nouncheckedindexedaccess"><code>noUncheckedIndexedAccess</code></a></li> <li><a href="#nopropertyaccessfromindexsignature"><code>noPropertyAccessFromIndexSignature</code></a></li> <li><a href="#noimplicitoverride"><code>noImplicitOverride</code></a></li> <p><a href="#dont-go-viral">Don’t go viral</a></p> <li><a href="#allowsyntheticdefaultimports"><code>allowSyntheticDefaultImports</code></a></li> <li><a href="#esmoduleinterop"><code>esModuleInterop</code></a></li> <li><a href="#skipdefaultlibcheck"><code>skipDefaultLibCheck</code></a></li> <li><a href="#useunknownincatchvariables"><code>useUnknownInCatchVariables</code></a></li> <li><a href="#but-sometimes-we-need-these-right">But sometimes we need these, right?</a></li> <li><a href="#is-mike-asking-me-to-take-on-tech-debt">Is Mike asking me to take on tech debt?</a></li> </ul></section></div><section class="post-body"><h2 id="whats-in-the-tsconfigjson" style="position:relative;"><a href="#whats-in-the-tsconfigjson" aria-label="whats in the tsconfigjson permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"/></svg></a>What’s in the <code>tsconfig.json</code>?</h2> <p>Let’s look closely at what we just did, and make sure we understand all of the parts that make up the whole</p> <h2 id="in-my-tsconfigjson-what-exactly-is-strict" style="position:relative;"><a href="#in-my-tsconfigjson-what-exactly-is-strict" aria-label="in my tsconfigjson what exactly is strict permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"/></svg></a>In my <code>tsconfig.json</code> what exactly is “strict”?</h2> <p>The source of truth is <a href="https://github.com/microsoft/TypeScript/blob/8d30552c65b9455e280374f329c2cd04c97208f9/src/compiler/commandLineParser.ts#L813">here</a>, and it’s important to know that this is a moving target</p> <h3 id="noimplicitany" style="position:relative;"><a href="#noimplicitany" aria-label="noimplicitany permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"/></svg></a><code>noImplicitAny</code></h3> <li>“Default to explicit” instead of “default to loose”</li> <li>This is not in any way restrictive, it only requires that we be explicit about <code>any</code></li> <h3 id="noimplicitthis" style="position:relative;"><a href="#noimplicitthis" aria-label="noimplicitthis permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"/></svg></a><code>noImplicitThis</code></h3> <li>There are certain places where <code>this</code> is important and non-inferrable</li> <p>Example: addEventListener</p> <pre class="shiki github-light twoslash lsp" style="background-color: #ffffff; color: #24292f"><div class="language-id">ts</div><div class="code-container"><code><div class="line"><span style="color: #CF222E">const</span><span style="color: #24292F"> </span><span style="color: #0550AE"><data-lsp lsp="const my_element: HTMLButtonElement">my_element</data-lsp></span><span style="color: #24292F"> </span><span style="color: #CF222E">=</span><span style="color: #24292F"> <data-lsp lsp="var document: Document">document</data-lsp>.</span><span style="color: #8250DF"><data-lsp lsp="(method) Document.createElement<"button">(tagName: "button", options?: ElementCreationOptions | undefined): HTMLButtonElement (+2 overloads)">createElement</data-lsp></span><span style="color: #24292F">(</span><span style="color: #0A3069">'button'</span><span style="color: #24292F">)</span></div><div class="line"><span style="color: #24292F"><data-lsp lsp="const my_element: HTMLButtonElement">my_element</data-lsp>.</span><span style="color: #8250DF"><data-lsp lsp="(method) HTMLButtonElement.addEventListener<"click">(type: "click", listener: (this: HTMLButtonElement, ev: MouseEvent) => any, options?: boolean | AddEventListenerOptions | undefined): void (+1 overload)">addEventListener</data-lsp></span><span style="color: #24292F">(</span><span style="color: #0A3069">'click'</span><span style="color: #24292F">, </span><span style="color: #CF222E">function</span><span style="color: #24292F"> (</span><span style="color: #953800"><data-lsp lsp="(parameter) e: MouseEvent">e</data-lsp></span><span style="color: #24292F">) {</span></div><div class="line"><span style="color: #24292F"> </span><span style="color: #0550AE">this</span></div><div class="meta-line"><span class="popover-prefix"/><span class="popover"><div class="arrow"/>this: HTMLButtonElement</span></div><div class="line"><span style="color: #24292F"> <data-lsp lsp="var console: Console">console</data-lsp>.</span><span style="color: #8250DF"><data-lsp lsp="(method) Console.log(...data: any[]): void">log</data-lsp></span><span style="color: #24292F">(</span><span style="color: #0550AE">this</span><span style="color: #24292F">.<data-lsp lsp="(property) Element.className: string">className</data-lsp>)</span></div><div class="line"><span style="color: #24292F"> </span><span style="color: #6E7781">// logs `true`</span></div><div class="line"><span style="color: #24292F"> <data-lsp lsp="var console: Console">console</data-lsp>.</span><span style="color: #8250DF"><data-lsp lsp="(method) Console.log(...data: any[]): void">log</data-lsp></span><span style="color: #24292F">(<data-lsp lsp="(parameter) e: MouseEvent">e</data-lsp>.<data-lsp lsp="(property) Event.currentTarget: EventTarget | null">currentTarget</data-lsp> </span><span style="color: #CF222E">===</span><span style="color: #24292F"> </span><span style="color: #0550AE">this</span><span style="color: #24292F">)</span></div><div class="line"><span style="color: #24292F">})</span></div></code><a class="playground-link try-code-link" target="_blank" href="https://www.typescriptlang.org/play/#code/PQgEFpIYwVwF0uAUFA9gOwM51AWwJ4D6ApgDbG7Ho4C8oAJqrJdQHRQBOxAhnMQKLkWcABQByAEbw4GMQEokBEkKpxW3evX4A3VQBkAltirEO4qKQNQA1mIA0oAGYx0UOAYygRxOaADeSKCgcAAWRkhgQQB6APyBoGhYqOSspKgA5iKhRuyk3JiYAHLclApBYGnpmKAABnAcMMQ18YmYycSpGd7sMBxc1AAq3BzpxLQ0dNmYCgC+ckA">Try</a></div></pre> <p>If we wanted to make it an independent function declaration and had <code>noImplicitThis</code> enabled, we’d be asked to provide a proper <code>this</code> type annotation</p> <pre class="shiki github-light twoslash lsp" style="background-color: #ffffff; color: #24292f"><div class="language-id">ts</div><div class="code-container"><code><div class="line"><span style="color: #CF222E">function</span><span style="color: #24292F"> </span><span style="color: #8250DF"><data-lsp lsp="function clickListener(e: MouseEvent): void">clickListener</data-lsp></span><span style="color: #24292F">(</span><span style="color: #953800"><data-lsp lsp="(parameter) e: MouseEvent">e</data-lsp></span><span style="color: #CF222E">:</span><span style="color: #24292F"> </span><span style="color: #953800"><data-lsp lsp="interface MouseEvent">MouseEvent</data-lsp></span><span style="color: #24292F">) {</span></div><div class="line"><span style="color: #24292F"> <data-lsp lsp="var console: Console">console</data-lsp>.</span><span style="color: #8250DF"><data-lsp lsp="(method) Console.log(...data: any[]): void">log</data-lsp></span><span style="color: #24292F">(</span><span style="color: #0550AE"><data-err>this</data-err></span><span style="color: #24292F">.<data-lsp lsp="any">className</data-lsp>)</span></div><span class="error"><span>'this' implicitly has type 'any' because it does not have a type annotation.</span><span class="code">2683</span></span><span class="error-behind">'this' implicitly has type 'any' because it does not have a type annotation.</span><div class="line"><span style="color: #24292F"> <data-lsp lsp="var console: Console">console</data-lsp>.</span><span style="color: #8250DF"><data-lsp lsp="(method) Console.log(...data: any[]): void">log</data-lsp></span><span style="color: #24292F">(<data-lsp lsp="(parameter) e: MouseEvent">e</data-lsp>.<data-lsp lsp="(property) Event.currentTarget: EventTarget | null">currentTarget</data-lsp> </span><span style="color: #CF222E">===</span><span style="color: #24292F"> </span><span style="color: #0550AE"><data-err>this</data-err></span><span style="color: #24292F">)</span></div><span class="error"><span>'this' implicitly has type 'any' because it does not have a type annotation.</span><span class="code">2683</span></span><span class="error-behind">'this' implicitly has type 'any' because it does not have a type annotation.</span><div class="line"><span style="color: #24292F">}</span></div></code><a class="playground-link try-code-link" target="_blank" href="https://www.typescriptlang.org/play/#code/PTAEAEFMCdoe2gZwFygEwDYAcBmAUAGYCuAdgMYAuAlnCaGQDZVkDWAMlYhZCTABSRUAWThFEkAKIA3HhQCUoAN55Q9WojgNIAOgZwA5nwoALTtsYBDRIgByFgLaQ5KtSQ1bdBgeaKxZAFQtofUgKUABeSNATTmcAXyA">Try</a></div></pre> <pre class="shiki github-light twoslash lsp" style="background-color: #ffffff; color: #24292f"><div class="language-id">ts</div><div class="code-container"><code><div class="line highlight"><span style="color: #CF222E">function</span><span style="color: #24292F"> </span><span style="color: #8250DF"><data-lsp lsp="function clickListener(this: HTMLButtonElement, e: MouseEvent): void">clickListener</data-lsp></span><span style="color: #24292F">(</span><span style="color: #0550AE"><data-lsp lsp="(parameter) this: HTMLButtonElement">this</data-lsp></span><span style="color: #CF222E">:</span><span style="color: #24292F"> </span><span style="color: #953800"><data-lsp lsp="interface HTMLButtonElement">HTMLButtonElement</data-lsp></span><span style="color: #24292F">, </span><span style="color: #953800"><data-lsp lsp="(parameter) e: MouseEvent">e</data-lsp></span><span style="color: #CF222E">:</span><span style="color: #24292F"> </span><span style="color: #953800"><data-lsp lsp="interface MouseEvent">MouseEvent</data-lsp></span><span style="color: #24292F">) {</span></div><div class="line dim"><span style="color: #24292F"> <data-lsp lsp="var console: Console">console</data-lsp>.</span><span style="color: #8250DF"><data-lsp lsp="(method) Console.log(...data: any[]): void">log</data-lsp></span><span style="color: #24292F">(</span><span style="color: #0550AE">this</span><span style="color: #24292F">.<data-lsp lsp="(property) Element.className: string">className</data-lsp>)</span></div><div class="line dim"><span style="color: #24292F"> <data-lsp lsp="var console: Console">console</data-lsp>.</span><span style="color: #8250DF"><data-lsp lsp="(method) Console.log(...data: any[]): void">log</data-lsp></span><span style="color: #24292F">(<data-lsp lsp="(parameter) e: MouseEvent">e</data-lsp>.<data-lsp lsp="(property) Event.currentTarget: EventTarget | null">currentTarget</data-lsp> </span><span style="color: #CF222E">===</span><span style="color: #24292F"> </span><span style="color: #0550AE">this</span><span style="color: #24292F">)</span></div><div class="line dim"><span style="color: #24292F">}</span></div></code><a class="playground-link try-code-link" target="_blank" href="https://www.typescriptlang.org/play/#code/GYVwdgxgLglg9mABBANjCBrAMjAzlAUzAICcAKKACzwC5EAJAFQFksAhEKKBAURQIC2RKABpEBOszghcBHgDdhASkQBvAFCJkCXHH4A6FHADmFarn2oAhrlwA5K0KWbtYXQaOmClkCRLDGKxJjAihEAF5IxCo8ZwBfIA">Try</a></div></pre> <h3 id="alwaysstrict" style="position:relative;"><a href="#alwaysstrict" aria-label="alwaysstrict permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"/></svg></a><code>alwaysStrict</code></h3> <li>JS “use strict”</li> <li>necessary for modern JS language features</li> <h3 id="strictbindcallapply" style="position:relative;"><a href="#strictbindcallapply" aria-label="strictbindcallapply permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"/></svg></a><code>strictBindCallApply</code></h3> <li>Bind, call, apply used to return very loosely-typed functions.</li> <li>No good reasons I’m aware of to disable this</li> <h3 id="strictnullchecks" style="position:relative;"><a href="#strictnullchecks" aria-label="strictnullchecks permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"/></svg></a><code>strictNullChecks</code></h3> <li>Without this enabled, <strong>all types allow <code>null</code> values</strong></li> <li>Leaving this disabled makes truthy/falsy type guards much less useful</li> <li>Operating without <code>strictNullChecks</code> is asking for runtime errors that could otherwise be caught at build time</li> <pre class="shiki github-light twoslash lsp" style="background-color: #ffffff; color: #24292f"><div class="language-id">ts</div><div class="code-container"><code><div class="line"><span style="color: #6E7781">// Without `strictNullChecks` enabled</span></div><div class="line"><span style="color: #CF222E">class</span><span style="color: #24292F"> </span><span style="color: #953800"><data-lsp lsp="class Animal">Animal</data-lsp></span><span style="color: #24292F"> {</span></div><div class="line"><span style="color: #24292F"> </span><span style="color: #8250DF"><data-lsp lsp="(method) Animal.run(): void">run</data-lsp></span><span style="color: #24292F">() {}</span></div><div class="line"><span style="color: #24292F">}</span></div><div class="line"><span style="color: #CF222E">let</span><span style="color: #24292F"> <data-lsp lsp="let animal: Animal" style="border-bottom: solid 2px lightgrey;">animal</data-lsp> </span><span style="color: #CF222E">=</span><span style="color: #24292F"> </span><span style="color: #CF222E">new</span><span style="color: #24292F"> </span><span style="color: #8250DF"><data-lsp lsp="constructor Animal(): Animal">Animal</data-lsp></span><span style="color: #24292F">()</span></div><div class="meta-line"><span class="popover-prefix"> </span><span class="popover"><div class="arrow"/>let animal: Animal</span></div><div class="line"><span style="color: #24292F"><data-lsp lsp="let animal: Animal">animal</data-lsp> </span><span style="color: #CF222E">=</span><span style="color: #24292F"> </span><span style="color: #0550AE">null</span><span style="color: #24292F"> </span><span style="color: #6E7781">// type-checks, but do we really want it to?</span></div></code><a class="playground-link try-code-link" target="_blank" href="https://www.typescriptlang.org/play/#code/PTAEAEGcBcCcEsDG0ByBXANhgwgCwKaIDWkAXKAGYCGGk+AUCKAOrzS4D2a0oABjAmToseQiV6h8AOyoAjDPgAm9RBiqRIoAIJT4AWxqgA3vVChYaKQAoAlMYC+9Rwp5VdBjKAC8oKfgDu2u40toxgZmYAegD89G76hj5SmJ5M0ACeAA74ALSIBMSQADSgstygihyg-vjm+DQY6dVuPGyg0BzRQA">Try</a></div></pre> <h3 id="strictfunctiontypes" style="position:relative;"><a href="#strictfunctiontypes" aria-label="strictfunctiontypes permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"/></svg></a><code>strictFunctionTypes</code></h3> <p>Some common-sense loopholes around matching function arguments during type-checking function values</p> <pre class="shiki github-light twoslash lsp" style="background-color: #ffffff; color: #24292f"><div class="language-id">ts</div><div class="code-container"><code><div class="line"><span style="color: #CF222E">abstract</span><span style="color: #24292F"> </span><span style="color: #CF222E">class</span><span style="color: #24292F"> </span><span style="color: #953800"><data-lsp lsp="class Animal">Animal</data-lsp></span><span style="color: #24292F"> {</span></div><div class="line"><span style="color: #24292F"> </span><span style="color: #CF222E">public</span><span style="color: #24292F"> </span><span style="color: #CF222E">abstract</span><span style="color: #24292F"> </span><span style="color: #CF222E">readonly</span><span style="color: #24292F"> </span><span style="color: #953800"><data-lsp lsp="(property) Animal.legs: number">legs</data-lsp></span><span style="color: #CF222E">:</span><span style="color: #24292F"> </span><span style="color: #0550AE">number</span></div><div class="line"><span style="color: #24292F">}</span></div><div class="line"><span style="color: #CF222E">class</span><span style="color: #24292F"> </span><span style="color: #953800"><data-lsp lsp="class Cat">Cat</data-lsp></span><span style="color: #24292F"> </span><span style="color: #CF222E">extends</span><span style="color: #24292F"> </span><span style="color: #0550AE"><data-lsp lsp="class Animal">Animal</data-lsp></span><span style="color: #24292F"> {</span></div><div class="line"><span style="color: #24292F"> </span><span style="color: #953800"><data-lsp lsp="(property) Cat.legs: number">legs</data-lsp></span><span style="color: #24292F"> </span><span style="color: #CF222E">=</span><span style="color: #24292F"> </span><span style="color: #0550AE">4</span></div><div class="line"><span style="color: #24292F"> </span><span style="color: #8250DF"><data-lsp lsp="(method) Cat.purr(): void">purr</data-lsp></span><span style="color: #24292F">() {</span></div><div class="line"><span style="color: #24292F"> <data-lsp lsp="var console: Console">console</data-lsp>.</span><span style="color: #8250DF"><data-lsp lsp="(method) Console.log(...data: any[]): void">log</data-lsp></span><span style="color: #24292F">(</span><span style="color: #0A3069">'purr'</span><span style="color: #24292F">)</span></div><div class="line"><span style="color: #24292F"> }</span></div><div class="line"><span style="color: #24292F">}</span></div><div class="line"><span style="color: #CF222E">class</span><span style="color: #24292F"> </span><span style="color: #953800"><data-lsp lsp="class Dog">Dog</data-lsp></span><span style="color: #24292F"> </span><span style="color: #CF222E">extends</span><span style="color: #24292F"> </span><span style="color: #0550AE"><data-lsp lsp="class Animal">Animal</data-lsp></span><span style="color: #24292F"> {</span></div><div class="line"><span style="color: #24292F"> </span><span style="color: #953800"><data-lsp lsp="(property) Dog.legs: number">legs</data-lsp></span><span style="color: #24292F"> </span><span style="color: #CF222E">=</span><span style="color: #24292F"> </span><span style="color: #0550AE">4</span></div><div class="line"><span style="color: #24292F"> </span><span style="color: #8250DF"><data-lsp lsp="(method) Dog.bark(): void">bark</data-lsp></span><span style="color: #24292F">() {</span></div><div class="line"><span style="color: #24292F"> <data-lsp lsp="var console: Console">console</data-lsp>.</span><span style="color: #8250DF"><data-lsp lsp="(method) Console.log(...data: any[]): void">log</data-lsp></span><span style="color: #24292F">(</span><span style="color: #0A3069">'arf'</span><span style="color: #24292F">)</span></div><div class="line"><span style="color: #24292F"> }</span></div><div class="line"><span style="color: #24292F">}</span></div><div class="line"> </div><div class="line"><span style="color: #CF222E">let</span><span style="color: #24292F"> </span><span style="color: #8250DF"><data-lsp lsp="let animalFn: (x: Animal) => void">animalFn</data-lsp></span><span style="color: #CF222E">!:</span><span style="color: #24292F"> (</span><span style="color: #953800"><data-lsp lsp="(parameter) x: Animal">x</data-lsp></span><span style="color: #CF222E">:</span><span style="color: #24292F"> </span><span style="color: #953800"><data-lsp lsp="class Animal">Animal</data-lsp></span><span style="color: #24292F">) </span><span style="color: #CF222E">=></span><span style="color: #24292F"> </span><span style="color: #0550AE">void</span></div><div class="line"><span style="color: #CF222E">let</span><span style="color: #24292F"> </span><span style="color: #8250DF"><data-lsp lsp="let dogFn: (x: Dog) => void">dogFn</data-lsp></span><span style="color: #CF222E">!:</span><span style="color: #24292F"> (</span><span style="color: #953800"><data-lsp lsp="(parameter) x: Dog">x</data-lsp></span><span style="color: #CF222E">:</span><span style="color: #24292F"> </span><span style="color: #953800"><data-lsp lsp="class Dog">Dog</data-lsp></span><span style="color: #24292F">) </span><span style="color: #CF222E">=></span><span style="color: #24292F"> </span><span style="color: #0550AE">void</span></div><div class="line"><span style="color: #CF222E">let</span><span style="color: #24292F"> </span><span style="color: #8250DF"><data-lsp lsp="let catFn: (x: Cat) => void">catFn</data-lsp></span><span style="color: #CF222E">!:</span><span style="color: #24292F"> (</span><span style="color: #953800"><data-lsp lsp="(parameter) x: Cat">x</data-lsp></span><span style="color: #CF222E">:</span><span style="color: #24292F"> </span><span style="color: #953800"><data-lsp lsp="class Cat">Cat</data-lsp></span><span style="color: #24292F">) </span><span style="color: #CF222E">=></span><span style="color: #24292F"> </span><span style="color: #0550AE">void</span></div><div class="line"> </div><div class="line"><span style="color: #24292F"><data-err><data-lsp lsp="let animalFn: (x: Animal) => void">animalFn</data-lsp></data-err> </span><span style="color: #CF222E">=</span><span style="color: #24292F"> <data-lsp lsp="let dogFn: (x: Dog) => void">dogFn</data-lsp> </span><span style="color: #6E7781">// Error with --strictFunctionTypes</span></div><span class="error"><span>Type '(x: Dog) => void' is not assignable to type '(x: Animal) => void'. Types of parameters 'x' and 'x' are incompatible. Property 'bark' is missing in type 'Animal' but required in type 'Dog'.</span><span class="code">2322</span></span><span class="error-behind">Type '(x: Dog) => void' is not assignable to type '(x: Animal) => void'. Types of parameters 'x' and 'x' are incompatible. Property 'bark' is missing in type 'Animal' but required in type 'Dog'.</span><div class="line"><span style="color: #24292F"><data-lsp lsp="let dogFn: (x: Dog) => void">dogFn</data-lsp> </span><span style="color: #CF222E">=</span><span style="color: #24292F"> <data-lsp lsp="let animalFn: (x: Animal) => void">animalFn</data-lsp> </span><span style="color: #6E7781">// Always ok</span></div><div class="line"><span style="color: #24292F"><data-err><data-lsp lsp="let dogFn: (x: Dog) => void">dogFn</data-lsp></data-err> </span><span style="color: #CF222E">=</span><span style="color: #24292F"> <data-lsp lsp="let catFn: (x: Cat) => void">catFn</data-lsp> </span><span style="color: #6E7781">// Always error</span></div><span class="error"><span>Type '(x: Cat) => void' is not assignable to type '(x: Dog) => void'. Types of parameters 'x' and 'x' are incompatible. Property 'purr' is missing in type 'Dog' but required in type 'Cat'.</span><span class="code">2322</span></span><span class="error-behind">Type '(x: Cat) => void' is not assignable to type '(x: Dog) => void'. Types of parameters 'x' and 'x' are incompatible. Property 'purr' is missing in type 'Dog' but required in type 'Cat'.</span></code><a class="playground-link try-code-link" target="_blank" href="https://www.typescriptlang.org/play/#code/PTAEAEFMCdoe2gZwFygEwGY1oFAEMAjRAF2jwGNjRyAbPRRUAQQDsBLAWzxtAG8dQg0AAcArgRptyoQiTKVQ0SHgAmcFjQCeoGpADmKUC1EcCMHAF8cteowDCeKpAAexSCxWNWnbnwE79RgBeUAAWfzFYAAoASj8hanVEOF0AOho4PSiAckjobJj-KysbBlAAEUzQFzcPL3YuHn5BXQNQEPDBAjxoAGtY+KFyJJTIdMycnoAzAqLLHBxdKjwG7gAxFgBCVCjnVG9GuKCAPlAANzg2FUXIKjU9De3QXdRKvSPTi6ubqnJHR52e1ADmIH3Ol2u+FWNA27VA91hIFAAFFYAhQAB3NjEAAWoAAtPi5FJiGtRCxKGx1AAVTTCSCIHAIlhwlY+GEspFMGgYvCaRhwXpMzKwkJ-UmcsDc3n86po6BAA">Try</a></div></pre> <p>If you took my Intermediate TypeScript course, you may recognize this as <strong>detecting when functions are <a href="../../intermediate-v2/10-covariance-contravariance/index.md">contravariant</a> over their argument types</strong>, and preventing a problematic assignment.</p> <h3 id="strictpropertyinitialization" style="position:relative;"><a href="#strictpropertyinitialization" aria-label="strictpropertyinitialization permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"/></svg></a><code>strictPropertyInitialization</code></h3> <p>Holds you to your promises around class fields really being “always there” vs. “sometimes undefined”</p> <pre class="shiki github-light twoslash lsp" style="background-color: #ffffff; color: #24292f"><div class="language-id">ts</div><div class="code-container"><code><div class="line"><span style="color: #CF222E">class</span><span style="color: #24292F"> </span><span style="color: #953800"><data-lsp lsp="class Car">Car</data-lsp></span><span style="color: #24292F"> {</span></div><div class="line"><span style="color: #24292F"> </span><span style="color: #953800"><data-err><data-lsp lsp="(property) Car.numDoors: number">numDoors</data-lsp></data-err></span><span style="color: #CF222E">:</span><span style="color: #24292F"> </span><span style="color: #0550AE">number</span></div><span class="error"><span>Property 'numDoors' has no initializer and is not definitely assigned in the constructor.</span><span class="code">2564</span></span><span class="error-behind">Property 'numDoors' has no initializer and is not definitely assigned in the constructor.</span><div class="line"><span style="color: #24292F">}</span></div></code><a class="playground-link try-code-link" target="_blank" href="https://www.typescriptlang.org/play/#code/PTAEAEFMCdoe2gZwFygEwFYBsAWAUAMYA2AhooqAMInSgDeeooAdgK4C2AInAiixwCMYeAL5A">Try</a></div></pre> <h2 id="even-more-strict" style="position:relative;"><a href="#even-more-strict" aria-label="even more strict permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"/></svg></a>Even more strict</h2> <h3 id="nounusedlocals" style="position:relative;"><a href="#nounusedlocals" aria-label="nounusedlocals permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"/></svg></a><code>noUnusedLocals</code></h3> <li>Busts you on unused local variables</li> <li>Better to have TS detect this rather than a linter</li> <h3 id="nounusedparameters" style="position:relative;"><a href="#nounusedparameters" aria-label="nounusedparameters permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"/></svg></a><code>noUnusedParameters</code></h3> <p>Function arguments you don’t use need to be prefixed with _</p> <pre class="shiki github-light twoslash lsp" style="background-color: #ffffff; color: #24292f"><div class="language-id">ts</div><div class="code-container"><code><div class="line"><span style="color: #CF222E">const</span><span style="color: #24292F"> </span><span style="color: #0550AE"><data-lsp lsp="const p: Promise<unknown>">p</data-lsp></span><span style="color: #24292F"> </span><span style="color: #CF222E">=</span><span style="color: #24292F"> </span><span style="color: #CF222E">new</span><span style="color: #24292F"> </span><span style="color: #0550AE"><data-lsp lsp="var Promise: PromiseConstructor new <unknown>(executor: (resolve: (value: unknown) => void, reject: (reason?: any) => void) => void) => Promise<unknown>">Promise</data-lsp></span><span style="color: #24292F">((</span><span style="color: #953800"><data-err><data-lsp lsp="(parameter) resolve: (value: unknown) => void">resolve</data-lsp></data-err></span><span style="color: #24292F">, </span><span style="color: #953800"><data-lsp lsp="(parameter) reject: (reason?: any) => void">reject</data-lsp></span><span style="color: #24292F">) </span><span style="color: #CF222E">=></span><span style="color: #24292F"> {</span></div><span class="error"><span>'resolve' is declared but its value is never read.</span><span class="code">6133</span></span><span class="error-behind">'resolve' is declared but its value is never read.</span><div class="line"><span style="color: #24292F"> </span><span style="color: #8250DF"><data-lsp lsp="(parameter) reject: (reason?: any) => void">reject</data-lsp></span><span style="color: #24292F">(</span><span style="color: #0A3069">"boom"</span><span style="color: #24292F">)</span></div><div class="line"><span style="color: #24292F">});</span></div></code><a class="playground-link try-code-link" target="_blank" href="https://www.typescriptlang.org/play/#code/PTAEAEFMCdoe2gZwFygGwEYDMWBQIIA7OAVUIFdFIATABQENp6BbSAFxkVwGM5DE2oAA6gAvKEKQA7qFrxmASyoAKZdEiI4AGwBukADSh1AK0jc2ASjEA+UAG9coI5FPnlAIgBGcOM3cXcAF8LAG4gA">Try</a></div></pre> <pre class="shiki github-light" style="background-color: #ffffff; color: #24292f"><div class="language-id">diff</div><div class="code-container"><code><div class="line"><span style="color: #82071E">- const p = new Promise((resolve, reject) => {</span></div><div class="line"><span style="color: #116329">+ const p = new Promise((_resolve, reject) => {</span></div></code></div></pre> <pre class="shiki github-light twoslash lsp" style="background-color: #ffffff; color: #24292f"><div class="language-id">ts</div><div class="code-container"><code><div class="line highlight"><span style="color: #CF222E">const</span><span style="color: #24292F"> </span><span style="color: #0550AE"><data-lsp lsp="const p: Promise<unknown>">p</data-lsp></span><span style="color: #24292F"> </span><span style="color: #CF222E">=</span><span style="color: #24292F"> </span><span style="color: #CF222E">new</span><span style="color: #24292F"> </span><span style="color: #0550AE"><data-lsp lsp="var Promise: PromiseConstructor new <unknown>(executor: (resolve: (value: unknown) => void, reject: (reason?: any) => void) => void) => Promise<unknown>">Promise</data-lsp></span><span style="color: #24292F">((</span><span style="color: #953800"><data-lsp lsp="(parameter) _resolve: (value: unknown) => void">_resolve</data-lsp></span><span style="color: #24292F">, </span><span style="color: #953800"><data-lsp lsp="(parameter) reject: (reason?: any) => void">reject</data-lsp></span><span style="color: #24292F">) </span><span style="color: #CF222E">=></span><span style="color: #24292F"> {</span></div><div class="line dim"><span style="color: #24292F"> </span><span style="color: #8250DF"><data-lsp lsp="(parameter) reject: (reason?: any) => void">reject</data-lsp></span><span style="color: #24292F">(</span><span style="color: #0A3069">"boom"</span><span style="color: #24292F">)</span></div><div class="line dim"><span style="color: #24292F">});</span></div></code><a class="playground-link try-code-link" target="_blank" href="https://www.typescriptlang.org/play/#code/PTAEAEDsHsFVIK4GcCmATACgQwE5YLYoAuKOSAUAMbSRJGgAOoAvKJCgO6gY7T4CWqABRCA+jhRJoAGwBuKADSgJAKxSUiAShYA+UAG9yoZSjUahAIgBG0Phc3kAvpoDcQA">Try</a></div></pre> <h3 id="noimplicitreturns" style="position:relative;"><a href="#noimplicitreturns" aria-label="noimplicitreturns permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"/></svg></a><code>noImplicitReturns</code></h3> <p>If any code paths return something explicitly, all code paths must return something explicitly. I’m a big fan of explicitly typing function boundaries, so I love this compiler setting</p> <h3 id="nofallthroughcasesinswitch" style="position:relative;"><a href="#nofallthroughcasesinswitch" aria-label="nofallthroughcasesinswitch permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"/></svg></a><code>noFallthroughCasesInSwitch</code></h3> <p><strong>I’m ok with this one as being <em>disabled</em></strong>, as I find case fall-throughs to be useful, important and easy (enough) to notice while reading code</p> <h3 id="types" style="position:relative;"><a href="#types" aria-label="types permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"/></svg></a><code>types</code></h3> <li>Instead of pulling in all @types/* packages, specify exactly what should be available</li> <li><strong>NOTE:</strong> this is nuanced, and only affects global scope (i.e., window, process) and auto-import.</li> <li><em>Why I care:</em> I don’t want types used exclusively in things like tests to be quite so readily available for accidental use in “app code”</li> <h3 id="stripinternal-most-important-for-libraries" style="position:relative;"><a href="#stripinternal-most-important-for-libraries" aria-label="stripinternal most important for libraries permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"/></svg></a><code>stripInternal</code> (most important for libraries)</h3> <li>Sometimes you need type information to only be available within a codebase.</li> <li><code>@internal</code> JSdoc tag surgically strips out type information for respective symbols</li> <h3 id="exactoptionalpropertytypes" style="position:relative;"><a href="#exactoptionalpropertytypes" aria-label="exactoptionalpropertytypes permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"/></svg></a><code>exactOptionalPropertyTypes</code></h3> <p>In essence, I think of this one as establishing some very reasonable rule of appropriate distinction between <code>null</code> and <code>undefined</code></p> <p>If we have a type like this</p> <pre class="shiki github-light twoslash lsp" style="background-color: #ffffff; color: #24292f"><div class="language-id">ts</div><div class="code-container"><code><div class="line"><span style="color: #CF222E">interface</span><span style="color: #24292F"> </span><span style="color: #953800"><data-lsp lsp="interface VideoPlayerPreferences">VideoPlayerPreferences</data-lsp></span><span style="color: #24292F"> {</span></div><div class="line"><span style="color: #24292F"> </span><span style="color: #953800"><data-lsp lsp="(property) VideoPlayerPreferences.volume?: number | undefined">volume</data-lsp></span><span style="color: #CF222E">?:</span><span style="color: #24292F"> </span><span style="color: #0550AE">number</span><span style="color: #24292F"> </span><span style="color: #6E7781">// 0 - 100, initially unset </span></div><div class="line"><span style="color: #24292F">}</span></div></code><a class="playground-link try-code-link" target="_blank" href="https://www.typescriptlang.org/play/#code/JYOwLgpgTgZghgYwgAgGrACYQPYAUA2cAntLlBDNBCEgM7IDeAUMsgG7b4CuAthAPwAuZCF4AjaMgD0U5AAZkAWmQBGOXIA0yUMDDA4+fEWRcQtCGGRMAvkA">Try</a></div></pre> <p>and enable <code>exactOptionalPropertyTypes</code>, we’ll be stopped from doing things like this</p> <pre class="shiki github-light twoslash lsp" style="background-color: #ffffff; color: #24292f"><div class="language-id">ts</div><div class="code-container"><code><div class="line"><span style="color: #CF222E">const</span><span style="color: #24292F"> </span><span style="color: #0550AE"><data-lsp lsp="const prefs: VideoPlayerPreferences">prefs</data-lsp></span><span style="color: #CF222E">:</span><span style="color: #24292F"> </span><span style="color: #953800"><data-lsp lsp="interface VideoPlayerPreferences">VideoPlayerPreferences</data-lsp></span><span style="color: #24292F"> </span><span style="color: #CF222E">=</span><span style="color: #24292F"> {</span></div><div class="line"><span style="color: #24292F"> <data-lsp lsp="(property) VideoPlayerPreferences.volume?: number">volume</data-lsp>: </span><span style="color: #0550AE">50</span></div><div class="line"><span style="color: #24292F">}</span></div><div class="line"><span style="color: #24292F"><data-err><data-lsp lsp="const prefs: VideoPlayerPreferences">prefs</data-lsp>.<data-lsp lsp="(property) VideoPlayerPreferences.volume?: number">volume</data-lsp></data-err> </span><span style="color: #CF222E">=</span><span style="color: #24292F"> </span><span style="color: #0550AE"><data-lsp lsp="var undefined">undefined</data-lsp></span><span style="color: #24292F"> </span><span style="color: #6E7781">// Bad practice</span></div><span class="error"><span>Type 'undefined' is not assignable to type 'number' with 'exactOptionalPropertyTypes: true'. Consider adding 'undefined' to the type of the target.</span><span class="code">2412</span></span><span class="error-behind">Type 'undefined' is not assignable to type 'number' with 'exactOptionalPropertyTypes: true'. Consider adding 'undefined' to the type of the target.</span><div class="line"><span style="color: #CF222E">delete</span><span style="color: #24292F"> <data-lsp lsp="const prefs: VideoPlayerPreferences">prefs</data-lsp>.<data-lsp lsp="(property) VideoPlayerPreferences.volume?: undefined">volume</data-lsp> </span><span style="color: #6E7781">// Good practice</span></div></code><a class="playground-link try-code-link" target="_blank" href="https://www.typescriptlang.org/play/#code/PTAEAEFMCdoe2gZwFygEwBYCMaBQIJIAPAQwGMAXAeQAcKBLOAOxIBsAFeGmCgTwBVe3RLnpMKMAGblIoAGr0AJpDjtWJXjE6RJMSEzKREoAN65QoAG5xWAVwC2kAPyomDgEYxQBAAygAtKBYPj4ANKBi9AxsrLygtkyIkBSguAC++AT+2WS2FNn+uGTMiCk00Doo8koqahpaFboVBkagALym5lY2DpCoAKw+6bjllQB01naO7fFMypJikIreYABCJMvl5AyGuMqsybKjkogTPdMEAOJwcJvQ2-SGQA">Try</a></div></pre> <p>What we’re seeing here is that we’re being stopped from explicitly setting an optional property to <code>undefined</code>. This is a good thing to prevent, because it causes some strangeness around things you’d expect to behave a certain way with undefined properties</p> <pre class="shiki github-light twoslash lsp" style="background-color: #ffffff; color: #24292f"><div class="language-id">ts</div><div class="code-container"><code><div class="line"><span style="color: #24292F"><data-lsp lsp="const prefs: VideoPlayerPreferences">prefs</data-lsp>.</span><span style="color: #8250DF"><data-lsp lsp="(method) Object.hasOwnProperty(v: PropertyKey): boolean">hasOwnProperty</data-lsp></span><span style="color: #24292F">(</span><span style="color: #0A3069">'volume'</span><span style="color: #24292F">) </span><span style="color: #6E7781">// returns TRUE</span></div><div class="line"><span style="color: #0550AE"><data-lsp lsp="var Object: ObjectConstructor">Object</data-lsp></span><span style="color: #24292F">.</span><span style="color: #8250DF"><data-lsp lsp="(method) ObjectConstructor.keys(o: {}): string[] (+1 overload)">keys</data-lsp></span><span style="color: #24292F">(<data-lsp lsp="const prefs: VideoPlayerPreferences">prefs</data-lsp>) </span><span style="color: #6E7781">// includes "volume"</span></div><div class="line"><span style="color: #CF222E">for</span><span style="color: #24292F"> (</span><span style="color: #CF222E">let</span><span style="color: #24292F"> <data-lsp lsp="let key: string">key</data-lsp> </span><span style="color: #CF222E">in</span><span style="color: #24292F"> <data-lsp lsp="const prefs: VideoPlayerPreferences">prefs</data-lsp>) {} </span><span style="color: #6E7781">// will iterate over "volume" key</span></div></code><a class="playground-link try-code-link" target="_blank" href="https://www.typescriptlang.org/play/#code/PTAEAEFMCdoe2gZwFygEwBYCMaBQIJIAPAQwGMAXAeQAcKBLOAOxIBsAFeGmCgTwBVe3RLnpMKMAGblIoAGr0AJpDjtWJXjE6RJMSEzKREoAN65QoAG5xWAVwC2kAPyomDgEYxQBAAygAtKBYPj4ANKBi9AxsrLygtkyIkBSguAC+uGTMiCk00Doo8koqahpa+br5BkagALym5lY2DpCoAKw+6fgE-r1kthS9-rh5BQB0ABYkiFQA7kyccNzQfAAUAOTWdo7rAJTeYPkUttCJoPwASgCqAKK4VO4AVpCUYwDWkLyIq6OSiPsEMRkOzKYwAIi2LTBuEkCFAq1YyVAHziYlAv3+pjSB1As3orFYEQk0BIElAcEsXghzUcYORnyAA">Try</a></div></pre> <p>The fact is, we <em>do</em> have a property on <code>prefs</code>, and it has a value. We’ve just made that value <code>undefined</code>.</p> <p>It’s <em>much</em> more appropriate to use <code>null</code> for these cases, since it’s an explicitly provided value that can’t be confused with the thing we get when we ask for properties that don’t exist.</p> <h3 id="nouncheckedindexedaccess" style="position:relative;"><a href="#nouncheckedindexedaccess" aria-label="nouncheckedindexedaccess permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"/></svg></a><code>noUncheckedIndexedAccess</code></h3> <p>Sometimes we can have object types which have some known properties as well as index signatures</p> <pre class="shiki github-light twoslash lsp" style="background-color: #ffffff; color: #24292f"><div class="language-id">ts</div><div class="code-container"><code><div class="line"><span style="color: #CF222E">interface</span><span style="color: #24292F"> </span><span style="color: #953800"><data-lsp lsp="interface PhoneBookEntry">PhoneBookEntry</data-lsp></span><span style="color: #24292F"> {</span></div><div class="line"><span style="color: #24292F"> </span><span style="color: #953800"><data-lsp lsp="(property) PhoneBookEntry.name: string">name</data-lsp></span><span style="color: #CF222E">:</span><span style="color: #24292F"> </span><span style="color: #0550AE">string</span></div><div class="line"><span style="color: #24292F"> </span><span style="color: #953800"><data-lsp lsp="(property) PhoneBookEntry.home_phone: string">home_phone</data-lsp></span><span style="color: #CF222E">:</span><span style="color: #24292F"> </span><span style="color: #0550AE">string</span></div><div class="line"><span style="color: #24292F"> </span><span style="color: #953800"><data-lsp lsp="(property) PhoneBookEntry.cell_phone: string">cell_phone</data-lsp></span><span style="color: #CF222E">:</span><span style="color: #24292F"> </span><span style="color: #0550AE">string</span></div><div class="line"><span style="color: #24292F"> [</span><span style="color: #953800"><data-lsp lsp="(parameter) k: string">k</data-lsp></span><span style="color: #CF222E">:</span><span style="color: #24292F"> </span><span style="color: #0550AE">string</span><span style="color: #24292F">]</span><span style="color: #CF222E">:</span><span style="color: #24292F"> </span><span style="color: #0550AE">string</span></div><div class="line"><span style="color: #24292F">}</span></div></code><a class="playground-link try-code-link" target="_blank" href="https://www.typescriptlang.org/play/#code/JYOwLgpgTgZghgYwgAgAoAsD2IICFOYDWAouFAJ7IDeAUMsiHALYQBcyAzmFKAOZ3IsLAPoAHLDnZceIfvSQAbBWIltO3PgIDahKRtkBdPTP4BfIA">Try</a></div></pre> <p>This rule ensures that <em>undeclared keys</em> have the <code>undefined</code> type added to them, to represent the possibility that no value is present</p> <pre class="shiki github-light twoslash lsp" style="background-color: #ffffff; color: #24292f"><div class="language-id">ts</div><div class="code-container"><code><div class="line"><span style="color: #CF222E">function</span><span style="color: #24292F"> </span><span style="color: #8250DF"><data-lsp lsp="function callback(phoneBook: PhoneBookEntry): void">callback</data-lsp></span><span style="color: #24292F">(</span><span style="color: #953800"><data-lsp lsp="(parameter) phoneBook: PhoneBookEntry">phoneBook</data-lsp></span><span style="color: #CF222E">:</span><span style="color: #24292F"> </span><span style="color: #953800"><data-lsp lsp="interface PhoneBookEntry">PhoneBookEntry</data-lsp></span><span style="color: #24292F">) {</span></div><div class="line"><span style="color: #24292F"> <data-lsp lsp="(parameter) phoneBook: PhoneBookEntry">phoneBook</data-lsp>.<data-lsp lsp="(property) PhoneBookEntry.name: string" style="border-bottom: solid 2px lightgrey;">name</data-lsp></span></div><div class="meta-line"><span class="popover-prefix"> </span><span class="popover"><div class="arrow"/>(property) PhoneBookEntry.name: string</span></div><div class="line"><span style="color: #24292F"> <data-lsp lsp="(parameter) phoneBook: PhoneBookEntry">phoneBook</data-lsp>.<data-lsp lsp="(index) PhoneBookEntry[string]: string | undefined" style="border-bottom: solid 2px lightgrey;">office_phone</data-lsp> </span><span style="color: #6E7781">// would have been `string`</span></div><div class="meta-line"><span class="popover-prefix"> </span><span class="popover"><div class="arrow"/>(index) PhoneBookEntry[string]: string | undefined</span></div><div class="line"><span style="color: #24292F">}</span></div></code><a class="playground-link try-code-link" target="_blank" href="https://www.typescriptlang.org/play/#code/PTAEAEDsHsFVIMYAsCmCDWKAmBJSWUAPbAQQQRQGdKAoAS0gBcUAnAMwEMLQAFJaSCgBC0aOgCiTFgE9QAbxqhQkDgFsUALlCVGLBgHNFofuoD6AB36CtOvZENKKAGycWrm7boNGA2uhte9gC6AXaGAL40IGAAtHEIAK6McTE0bAmIjHQCoAgcLgBGXOgAFJYCwqL+vO4iYpK60gCU8kblgnXoAHQq6lFgSoNDSgB6APxttVVd0GxsdBRuFaAgoADu0AlOWMYcAG4ooAUoKJCgAAa2Buf9w3eg4zThQA">Try</a></div></pre> <h3 id="nopropertyaccessfromindexsignature" style="position:relative;"><a href="#nopropertyaccessfromindexsignature" aria-label="nopropertyaccessfromindexsignature permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"/></svg></a><code>noPropertyAccessFromIndexSignature</code></h3> <p>This rule draws a distinction between <code>.foo</code> syntax (to be used for known property access) and <code>["foo"]</code> syntax (to be used for index signatures). Using the same example from above</p> <pre class="shiki github-light twoslash lsp" style="background-color: #ffffff; color: #24292f"><div class="language-id">ts</div><div class="code-container"><code><div class="line"><span style="color: #CF222E">function</span><span style="color: #24292F"> </span><span style="color: #8250DF"><data-lsp lsp="function callback(phoneBook: PhoneBookEntry): void">callback</data-lsp></span><span style="color: #24292F">(</span><span style="color: #953800"><data-lsp lsp="(parameter) phoneBook: PhoneBookEntry">phoneBook</data-lsp></span><span style="color: #CF222E">:</span><span style="color: #24292F"> </span><span style="color: #953800"><data-lsp lsp="interface PhoneBookEntry">PhoneBookEntry</data-lsp></span><span style="color: #24292F">) {</span></div><div class="line"><span style="color: #24292F"> <data-lsp lsp="(parameter) phoneBook: PhoneBookEntry">phoneBook</data-lsp>.<data-lsp lsp="(property) PhoneBookEntry.name: string" style="border-bottom: solid 2px lightgrey;">name</data-lsp></span></div><div class="meta-line"><span class="popover-prefix"> </span><span class="popover"><div class="arrow"/>(property) PhoneBookEntry.name: string</span></div><div class="line"><span style="color: #24292F"> <data-lsp lsp="(parameter) phoneBook: PhoneBookEntry">phoneBook</data-lsp>.<data-err><data-lsp lsp="(index) PhoneBookEntry[string]: string" style="border-bottom: solid 2px lightgrey;">office_phone</data-lsp></data-err> </span><span style="color: #6E7781">// would have been `string`</span></div><span class="error"><span>Property 'office_phone' comes from an index signature, so it must be accessed with ['office_phone'].</span><span class="code">4111</span></span><span class="error-behind">Property 'office_phone' comes from an index signature, so it must be accessed with ['office_phone'].</span><div class="meta-line"><span class="popover-prefix"> </span><span class="popover"><div class="arrow"/>(index) PhoneBookEntry[string]: string</span></div><div class="line"><span style="color: #24292F">}</span></div></code><a class="playground-link try-code-link" target="_blank" href="https://www.typescriptlang.org/play/#code/PTAEAEFMCdoe2gZwFygCwEYsCgQQHZwAK8ADjAC4CeAggMZ2SKIBi8AtgJL4AmkAHgGUAlgHN8AQwoBXaJGzD8FGADMJjUEQAWcfJABCcOAGsAokuhVQAb2yhQk9pFSIK0RaLugdTgPqkdPRc3Dy9GABtw-0DnUFd3fE97AG1jYITRAF100IBfXDwAWmK6aQpiwuwVaXw6CmFdUDoJSIAjdWMACgDdAyM0zRjDE3M3KgBKGy8evWHjADpHeTx7VbX7AD0Afmmh-vm4FRVhRmje0DwAdzhpcJ5vCQA3SFBWyEh8UAADeI8vgvWgNA22wuSAA">Try</a></div></pre> <h3 id="noimplicitoverride" style="position:relative;"><a href="#noimplicitoverride" aria-label="noimplicitoverride permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"/></svg></a><code>noImplicitOverride</code></h3> <p>The <code>override</code> keyword prevents incomplete refactors and other kinds of errors relating to object-oriented inheritance</p> <pre class="shiki github-light twoslash lsp" style="background-color: #ffffff; color: #24292f"><div class="language-id">ts</div><div class="code-container"><code><div class="line"><span style="color: #CF222E">class</span><span style="color: #24292F"> </span><span style="color: #953800"><data-lsp lsp="class Animal">Animal</data-lsp></span><span style="color: #24292F"> {</span></div><div class="line"><span style="color: #24292F"> </span><span style="color: #8250DF"><data-lsp lsp="(method) Animal.walk(): void">walk</data-lsp></span><span style="color: #24292F">() {}</span></div><div class="line"><span style="color: #24292F">}</span></div><div class="line"> </div><div class="line"><span style="color: #CF222E">class</span><span style="color: #24292F"> </span><span style="color: #953800"><data-lsp lsp="class Dog">Dog</data-lsp></span><span style="color: #24292F"> </span><span style="color: #CF222E">extends</span><span style="color: #24292F"> </span><span style="color: #0550AE"><data-lsp lsp="class Animal">Animal</data-lsp></span><span style="color: #24292F"> {</span></div><div class="line"><span style="color: #24292F"> </span><span style="color: #CF222E">override</span><span style="color: #24292F"> </span><span style="color: #8250DF"><data-lsp lsp="(method) Dog.walk(): void">walk</data-lsp></span><span style="color: #24292F">() {}</span></div><div class="line"><span style="color: #24292F">}</span></div></code><a class="playground-link try-code-link" target="_blank" href="https://www.typescriptlang.org/play/#code/MYGwhgzhAECCB2BLAtmE0DeAoa0DuaA1gBQCUmAvllVqJDACID2A5tAKYAeALu-ACYwEKNJhzQmAN3YAnGYn7t8RMpWpA">Try</a></div></pre> <p>if we make this change to <code>Animal</code></p> <pre class="shiki github-light" style="background-color: #ffffff; color: #24292f"><div class="language-id">diff</div><div class="code-container"><code><div class="line"><span style="color: #82071E">- walk() {}</span></div><div class="line"><span style="color: #116329">+ run() {}</span></div></code></div></pre> <p>We’ll be appropriately alerted</p> <pre class="shiki github-light twoslash lsp" style="background-color: #ffffff; color: #24292f"><div class="language-id">ts</div><div class="code-container"><code><div class="line"><span style="color: #CF222E">class</span><span style="color: #24292F"> </span><span style="color: #953800"><data-lsp lsp="class Animal">Animal</data-lsp></span><span style="color: #24292F"> {</span></div><div class="line"><span style="color: #24292F"> </span><span style="color: #8250DF"><data-lsp lsp="(method) Animal.run(): void">run</data-lsp></span><span style="color: #24292F">() {}</span></div><div class="line"><span style="color: #24292F">}</span></div><div class="line"> </div><div class="line"><span style="color: #CF222E">class</span><span style="color: #24292F"> </span><span style="color: #953800"><data-lsp lsp="class Dog">Dog</data-lsp></span><span style="color: #24292F"> </span><span style="color: #CF222E">extends</span><span style="color: #24292F"> </span><span style="color: #0550AE"><data-lsp lsp="class Animal">Animal</data-lsp></span><span style="color: #24292F"> {</span></div><div class="line"><span style="color: #24292F"> </span><span style="color: #CF222E">override</span><span style="color: #24292F"> </span><span style="color: #8250DF"><data-err><data-lsp lsp="(method) Dog.walk(): void">walk</data-lsp></data-err></span><span style="color: #24292F">() {}</span></div><span class="error"><span>This member cannot have an 'override' modifier because it is not declared in the base class 'Animal'.</span><span class="code">4113</span></span><span class="error-behind">This member cannot have an 'override' modifier because it is not declared in the base class 'Animal'.</span><div class="line"><span style="color: #24292F">}</span></div></code><a class="playground-link try-code-link" target="_blank" href="https://www.typescriptlang.org/play/#code/PTAEAEFMCdoe2gZwFygCwEYMGYBQBjAGwENFFQBBAOwEsBbYw0Ab11FGgFcqAKAShYBfXMIIkyoACJwA5qEgAPAC6QqAE3LV6jFm1BwAbjGg01kUAHdGAa35CRQA">Try</a></div></pre> <p>So this <code>override</code> keyword is quite valuable — we just need to make sure we put it in place where appropriate. <code>noImplicitOverride</code> helps guide us to do just that.</p> <pre class="shiki github-light twoslash lsp" style="background-color: #ffffff; color: #24292f"><div class="language-id">ts</div><div class="code-container"><code><div class="line"><span style="color: #CF222E">class</span><span style="color: #24292F"> </span><span style="color: #953800"><data-lsp lsp="class Animal">Animal</data-lsp></span><span style="color: #24292F"> {</span></div><div class="line"><span style="color: #24292F"> </span><span style="color: #8250DF"><data-lsp lsp="(method) Animal.walk(): void">walk</data-lsp></span><span style="color: #24292F">() {}</span></div><div class="line"><span style="color: #24292F">}</span></div><div class="line"> </div><div class="line"><span style="color: #CF222E">class</span><span style="color: #24292F"> </span><span style="color: #953800"><data-lsp lsp="class Dog">Dog</data-lsp></span><span style="color: #24292F"> </span><span style="color: #CF222E">extends</span><span style="color: #24292F"> </span><span style="color: #0550AE"><data-lsp lsp="class Animal">Animal</data-lsp></span><span style="color: #24292F"> {</span></div><div class="line"><span style="color: #24292F"> </span><span style="color: #8250DF"><data-err><data-lsp lsp="(method) Dog.walk(): void">walk</data-lsp></data-err></span><span style="color: #24292F">() {}</span></div><span class="error"><span>This member must have an 'override' modifier because it overrides a member in the base class 'Animal'.</span><span class="code">4114</span></span><span class="error-behind">This member must have an 'override' modifier because it overrides a member in the base class 'Animal'.</span><div class="line"><span style="color: #24292F">}</span></div></code><a class="playground-link try-code-link" target="_blank" href="https://www.typescriptlang.org/play/#code/PTAEAEDsHsEkFsAOAbAlgY1QFwPIDcBTAJyNQBMCAoECYo6IgZwC5QAWARg7cvWQENGjUAEFIqeP2SgA3pVCgA7lIDWACgCUsgL6VdvAUNAARaAHNQBAB5YCkMsLESps+UtWadeoA">Try</a></div></pre> <h2 id="dont-go-viral" style="position:relative;"><a href="#dont-go-viral" aria-label="dont go viral permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"/></svg></a>Don’t go viral</h2> <p>There are some compiler options that I <em>really dislike</em> when used in libraries, because they have a high probability of “infecting” any consumer and depriving them from making choices about their own codebase</p> <h3 id="allowsyntheticdefaultimports" style="position:relative;"><a href="#allowsyntheticdefaultimports" aria-label="allowsyntheticdefaultimports permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"/></svg></a><code>allowSyntheticDefaultImports</code></h3> <p>Allows you to import CommonJS modules as if they’re ES modules with a default export</p> <h3 id="esmoduleinterop" style="position:relative;"><a href="#esmoduleinterop" aria-label="esmoduleinterop permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"/></svg></a><code>esModuleInterop</code></h3> <p>Adds some runtime support for CJS/ESM interop, and enables allowSyntheticDefaultImports</p> <h3 id="skipdefaultlibcheck" style="position:relative;"><a href="#skipdefaultlibcheck" aria-label="skipdefaultlibcheck permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"/></svg></a><code>skipDefaultLibCheck</code></h3> <p>This effectively ignores potential breaking changes that stem from your node_modules types mixing with your own types. Particularly if you’re building a library, you need to know that if you “hide” this problem they’ll still “feel” it (and probably need to “skip” too)</p> <h3 id="useunknownincatchvariables" style="position:relative;"><a href="#useunknownincatchvariables" aria-label="useunknownincatchvariables permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"/></svg></a><code>useUnknownInCatchVariables</code></h3> <p>Caught throwables in a catch block will be typed as <code>unknown</code> instead of <code>any</code>, promoting better error-handling hygiene</p> <pre class="shiki github-light twoslash lsp" style="background-color: #ffffff; color: #24292f"><div class="language-id">ts</div><div class="code-container"><code><div class="line"><span style="color: #CF222E">try</span><span style="color: #24292F"> {} </span></div><div class="line"><span style="color: #CF222E">catch</span><span style="color: #24292F"> (<data-lsp lsp="var err: unknown" style="border-bottom: solid 2px lightgrey;">err</data-lsp>) { }</span></div><div class="meta-line"><span class="popover-prefix"> </span><span class="popover"><div class="arrow"/>var err: unknown</span></div></code><a class="playground-link try-code-link" target="_blank" href="https://www.typescriptlang.org/play/#code/PTAEAEFcGcFMFUB2BrRB7A7ogkogwgIYAuAxgBYBqBATgJYEBGANrNAFyhHWSwBQXAT1ABvAL6heJYuVAAKWNWoBKEaFG8QoLdoB6AfiA">Try</a></div></pre> <h3 id="but-sometimes-we-need-these-right" style="position:relative;"><a href="#but-sometimes-we-need-these-right" aria-label="but sometimes we need these right permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"/></svg></a>But sometimes we need these, right?</h3> <p>I have never found a good reason to enable these options in well-structured TS code.</p> <p><code>allowSyntheticDefaultImports</code> and <code>esModuleInterop</code> aim to allow patterns like</p> <pre class="shiki github-light" style="background-color: #ffffff; color: #24292f"><div class="language-id">ts</div><div class="code-container"><code><div class="line"><span style="color: #CF222E">import</span><span style="color: #24292F"> fs </span><span style="color: #CF222E">from</span><span style="color: #24292F"> </span><span style="color: #0A3069">'fs'</span></div></code></div></pre> <p>in situations where <code>fs</code> doesn’t actually expose an ES module <code>export default</code>. It exports a <em>namespace</em> of filesystem-related functions. Thankfully, even with these flags <em>both</em> disabled, we can still use a namespace import:</p> <pre class="shiki github-light" style="background-color: #ffffff; color: #24292f"><div class="language-id">ts</div><div class="code-container"><code><div class="line"><span style="color: #CF222E">import</span><span style="color: #24292F"> </span><span style="color: #0550AE">*</span><span style="color: #24292F"> </span><span style="color: #CF222E">as</span><span style="color: #24292F"> fs </span><span style="color: #CF222E">from</span><span style="color: #24292F"> </span><span style="color: #0A3069">'fs'</span></div></code></div></pre> <p>Now there are rare situations where some CommonJS code exports a single non-namespace thing in a way like</p> <pre class="shiki github-light" style="background-color: #ffffff; color: #24292f"><div class="language-id">ts</div><div class="code-container"><code><div class="line"><span style="color: #0550AE">module</span><span style="color: #24292F">.</span><span style="color: #0550AE">exports</span><span style="color: #24292F"> </span><span style="color: #CF222E">=</span><span style="color: #24292F"> </span><span style="color: #CF222E">function</span><span style="color: #24292F"> </span><span style="color: #8250DF">add</span><span style="color: #24292F">(</span><span style="color: #953800">a</span><span style="color: #24292F">, </span><span style="color: #953800">b</span><span style="color: #24292F">) {</span></div><div class="line"><span style="color: #24292F"> </span><span style="color: #CF222E">return</span><span style="color: #24292F"> a </span><span style="color: #CF222E">+</span><span style="color: #24292F"> b</span></div><div class="line"><span style="color: #24292F">}</span></div></code></div></pre> <p>add is definitely not a namespace, and</p> <pre class="shiki github-light" style="background-color: #ffffff; color: #24292f"><div class="language-id">ts</div><div class="code-container"><code><div class="line"><span style="color: #CF222E">import</span><span style="color: #24292F"> </span><span style="color: #0550AE">*</span><span style="color: #24292F"> </span><span style="color: #CF222E">as</span><span style="color: #24292F"> add </span><span style="color: #CF222E">from</span><span style="color: #24292F"> </span><span style="color: #0A3069">'./calculator'</span></div></code></div></pre> <p>WILL NOT WORK. There’s a TS-specific pattern that <em>will work</em> though — it’s a little weird, but it doesn’t require turning any compiler options on</p> <pre class="shiki github-light" style="background-color: #ffffff; color: #24292f"><div class="language-id">ts</div><div class="code-container"><code><div class="line"><span style="color: #CF222E">import</span><span style="color: #24292F"> add </span><span style="color: #CF222E">=</span><span style="color: #24292F"> </span><span style="color: #CF222E">require</span><span style="color: #24292F">(</span><span style="color: #0A3069">'./calculator'</span><span style="color: #24292F">)</span></div></code></div></pre> <h3 id="is-mike-asking-me-to-take-on-tech-debt" style="position:relative;"><a href="#is-mike-asking-me-to-take-on-tech-debt" aria-label="is mike asking me to take on tech debt permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"/></svg></a>Is Mike asking me to take on tech debt?</h3> <p>You may be thinking “these don’t look like ES modules”, and “won’t the TS team standardize on ES modules later?”</p>
推荐文章
耍酷的炒饭
·
在@Scheduled( .yml =变量)中使用cron变量_使用yml文件中的变量_Rails -在yml文件中使用ENV变量 - 腾讯云开发者社区 - 腾讯云
1 月前
近视的茶壶
·
如何使用Pandas DataFrame更新数据库表中的现有行?_如何在现有的PostgreSQL表中插入pandas DataFrame?_向Pandas dataframe中的现有文件追加新行 -
2 月前
快乐的剪刀
·
Adobe Photoshop CS5怎么破解序列号? - 系统之家
2 月前
卖萌的伏特加
·
装配式建筑网
4 月前
火星上的羽毛球
·
海南反季节瓜菜安全链缘何断裂
1 年前