34.2 Configuring typescript-eslint: Recommended and Strict Presets
Right, let’s talk about linting TypeScript. You’ve got the TypeScript compiler (tsc) yelling at you about types, which is great, but it’s utterly silent on a million other things that make code good—like code style, potential runtime errors, and patterns that just smell funny. That’s where typescript-eslint comes in. It’s the linter that actually understands your types, and configuring it is the difference between a gentle guide and a chaotic free-for-all.
The first thing you need to know is that you don’t start from scratch. Anyone who tells you to manually enable hundreds of rules one-by-one is either a masochist or lying to you. You start with a preset. The two heavyweights are @typescript-eslint/eslint-plugin/recommended and @typescript-eslint/eslint-plugin/strict.
The “Recommended” Preset: Your Sensible Default
Think of the recommended preset as the curated, “sensible defaults” package. It’s a fantastic starting point that catches a ton of common errors without being overly opinionated on style. It’s the config you show your manager to prove this linting thing is a good idea.
What makes it great? It focuses on rules that prevent bugs or are type-aware. For example, it enables no-unused-vars. But here’s the kicker: the core ESLint no-unused-vars rule is famously terrible with TypeScript because it doesn’t understand type declarations. The recommended preset turns off the core rule and turns on the @typescript-eslint/no-unused-vars rule, which actually understands your types. This alone is worth the price of admission.
Your .eslintrc.js will look something like this:
module.exports = {
parser: '@typescript-eslint/parser',
parserOptions: {
project: './tsconfig.json', // Critical for type-aware rules!
},
plugins: ['@typescript-eslint'],
extends: [
'eslint:recommended', // First, get the base JS rules
'plugin:@typescript-eslint/recommended', // Then layer on TS rules
],
};
Notice the parserOptions.project—it’s the magic key that unlocks the linter’s full type-aware powers. It tells the linter which tsconfig.json to use to understand your project’s types. Forgetting this is the number one cause of “why isn’t this rule working?!” problems.
The “Strict” Preset: For the Perfectionists Among Us
If recommended is sensible, strict is… well, strict. It’s for teams and projects that want the absolute highest level of code safety and consistency. It enables a whole extra batch of rules that are more opinionated and pedantic.
This includes glorious rules like no-non-null-assertion (that ! operator you keep using to shut up the compiler? Yeah, it hates that) and no-unnecessary-type-assertion (it’ll call you out for using as when the type is already obvious). Using this preset is like having a brilliant, incredibly annoying pair programmer who is always right.
You enable it by swapping out recommended for strict:
module.exports = {
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/strict', // Welcome to the party, pal.
],
// ... rest of config
};
A word of warning: adopting the strict preset on an existing codebase is a recipe for a thousand errors. It’s a fantastic goal, but you should introduce it gradually, maybe even using eslint-disable comments to temporarily squelch the firehose of failures until you can fix them properly.
Picking Your Battles: Extending and Overriding
The real power move isn’t just picking a preset; it’s knowing how to customize it. No preset is perfect for every project. You will 100% need to override things.
For instance, the strict preset’s no-non-null-assertion rule is fantastic in theory. In practice, sometimes you know a value exists (e.g., from a backend API response you control) and the type system can’t guarantee it. You might decide that rule is too aggressive for your project. So you turn it off:
module.exports = {
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/strict',
],
rules: {
// I acknowledge your opinion but will be ignoring it here, thank you.
'@typescript-eslint/no-non-null-assertion': 'off',
// Or maybe you just want a warning, not an error
'@typescript-eslint/no-unnecessary-type-assertion': 'warn',
},
};
The best practice is to start with recommended, get your CI pipeline happy with that, and then gradually enable rules from the strict preset that make sense for your team’s tolerance level. This iterative approach is far less painful than trying to boil the ocean on day one. Remember, the goal is to help you write better code, not to win a linter configuration contest.