We ran three typescript-eslint presets on a real open-source TypeScript library and counted every finding and second. The jump to strict was smaller than the jump to type-aware linting, and the findings themselves tell you whether your team is ready.
7 min read
typescript-eslint recommended vs strict-type-checked: which one should your project use? We ran both, plus recommended-type-checked in between, on the real ky HTTP library. recommended found 25 issues in 0.89 s. strict-type-checked found 104 in 2.09 s. Most of the extra time comes from type information, not from strictness.
That 4x jump in findings sounds scary. But when we read through them, a lot were style opinions rather than bugs, and a few were real signals. Here is exactly what we ran, what each preset caught, and how to choose without drowning your team in red squiggles.
The typescript-eslint docs describe a ladder of shared configs:
no-unsafe-* family.Two warnings from the docs matter here. First, the strict configs are not considered stable under semver, so a minor typescript-eslint update can add rules and new errors. Second, the docs suggest strict only if "a nontrivial percentage" of your developers are "highly proficient in TypeScript".
On typescript-eslint 8.72.1, we counted how many @typescript-eslint/ rules each preset turns on: recommended 20, recommended-type-checked 43, strict 28 and strict-type-checked 70.
.ts files and 4,917 lines in source/. tsc --noEmit passed cleanly before we started.latest, published 26 October 2026), ESLint 9.39.5, TypeScript 5.9.3, Node.js 24.22.1, on an 8-core x86_64 Linux box.tseslint.config() scoped to source/**/*.ts. The two type-checked ones enable parserOptions.projectService: true, as the typed-linting guide recommends.eslint-disable comments written for xo and unicorn rules. We turned off unused-directive reporting and excluded three "rule definition not found" messages for unicorn rules, because they come from the setup, not from the presets.npx eslint -c <config> source -f json per preset, reporting the median.| Preset | Findings | Files with findings | Median time (5 runs) |
|---|---|---|---|
| recommended | 25 | 3 | 0.89 s |
| recommended-type-checked | 75 | 6 | 1.94 s |
| strict-type-checked | 104 | 15 | 2.09 s |
recommended (25): no-explicit-any 14 times (9 in merge.ts, 4 in type-guards.ts, 1 in Ky.ts), no-unused-vars 10 times (all in Ky.ts) and prefer-const once.
recommended-type-checked (+50): the type checker turned up the unsafe-any chain. That's no-unsafe-member-access 23, no-unsafe-assignment 12, no-unsafe-return 4 and no-unsafe-argument 4. There were also 5 no-unnecessary-type-assertion hits, all auto-fixable, plus 1 require-await and 1 unbound-method. Most of the unsafe-any findings trace back to the same any-typed helpers that recommended had already flagged in merge.ts and type-guards.ts. Fix the source any, and many of these go away together.
strict-type-checked (+29):
no-unnecessary-condition 11. For example, "Unnecessary optional chain on a non-nullish value" in Ky.ts, and a check flagged as "always falsy" in constants.ts.no-invalid-void-type 10, mostly hook types like Request | Response | void | Promise<...> in hooks.ts.no-non-null-assertion 4, such as this.#abortController!.signal in Ky.ts.restrict-template-expressions 3, flagging numbers placed in template strings in error messages.no-unnecessary-type-parameters 1.Mostly not, in this repo, and that's the honest answer. ky deliberately uses void in hook return types so that hooks can return nothing. Putting a status-code number in an error message template is intended. The four non-null assertions sit on fields the code sets up before use. A strict preset flags these patterns because they can hide bugs, not because they always do.
The no-unnecessary-condition hits are the most interesting group. Each one says TypeScript believes a check can never fail. That means either the check is dead code or the types are looser than the runtime reality, and both are worth a look. In our run, that was the most useful rule strict-type-checked added.
Yes. Going from recommended to recommended-type-checked more than doubled the median time, from 0.89 s to 1.94 s, and tripled the findings. Going on to strict-type-checked added only 0.15 s more on our box. That makes sense: building the TypeScript program is the expensive part, and once it exists, more rules are cheap. On a 4,917-line library the difference is only seconds. On a large monorepo the type-aware step is the one to watch in CI.
This is the shape of the strict-type-checked config we ran. It follows the typed-linting guide:
For the other two runs we swapped strictTypeChecked for recommendedTypeChecked, or for recommended with the parserOptions block removed, because recommended doesn't need type information. You can also stack stylisticTypeChecked on top, but we left it out because it's about style, not correctness.
Based on our run, the cheapest order is:
any sources first. On ky, 14 no-explicit-any hits were the upstream cause of most of the 43 no-unsafe-* findings. Typing those helpers as unknown and narrowing them clears findings in several rules at once.eslint --fix handled the 5 no-unnecessary-type-assertion findings, the only fixable ones in our run.@typescript-eslint/no-invalid-void-type to off if your API intentionally uses void in unions, as ky's hooks do. That one change would have removed 10 of the 29 strict-only findings.no-unnecessary-condition. In our run it found checks that the types say can never fail, and those are the ones worth reading.recommended, or better, recommendedTypeChecked. On our run the type-aware step found the any leaks, which are the most bug-prone pattern.strictTypeChecked, but add it in a separate PR, fix or disable rules one at a time, and pin your typescript-eslint version so a minor update can't add surprise errors.If you're also considering other linters, see oxlint vs ESLint and Biome vs ESLint + Prettier. For a rule that recently tightened, our page on typescript-eslint 8.71 and no-unsafe-enum-assignment shows how a single release can change your error count.
Does strict-type-checked include recommended? Yes. It contains recommended, recommended-type-checked and strict.
Is strict-type-checked stable across minor versions? No. The docs say the strict configs are not semver-stable, so pin your version.
Why is type-checked linting slower? It builds a TypeScript program first. On our run that took the median from 0.89 s to 1.94 s.
Can I use strict without type checking? Yes. The strict preset needs no type information.
What did strict-type-checked add on ky? 29 findings beyond recommended-type-checked, led by no-unnecessary-condition (11) and no-invalid-void-type (10).
Lab evidence
Measured on 3 Nov 2026 on our box (x86_64, 8 cores, Node v24.22.1). We used sindresorhus/ky at commit 3541888 (package version 2.2.0, 31 .ts files and 4,917 lines in source/), with typescript-eslint 8.72.1, ESLint 9.39.5 and TypeScript 5.9.3. We timed 5 runs of each preset and report the median. ky lints with xo in real life, not these presets, so many findings are deliberate choices rather than bugs.
Explore the product
Freelancers and devs who want to turn coding skills into paid site builds
Both cut a string at a separator, but they fail in different ways. We ran them on Python 3.13.5 to show where partition() is safer and where split() is the right tool.
Summary2 Nov 20263 min read
What changes when you swap sort() for toSorted(), with a real 1-million-item Node.js benchmark and the support table.
Summary1 Nov 20263 min read
Dragging videos is the official way to change a playlist's order. Here are the steps from YouTube Help, where to find them in YouTube Studio, and the cases where reordering will not work.
Summary31 Oct 20263 min read