TYPESCRIPT
TypeScript ESLint: Syntax, Usage, and Examples
ESLint is a linting tool that helps you catch bugs, style issues, and risky patterns in your TypeScript code before they ship. You configure rules once, then ESLint checks your files automatically as you code or during builds.
How to Use ESLint with TypeScript
ESLint works by reading your files, applying a set of rules, and reporting problems as warnings or errors. In a TypeScript project, you typically pair ESLint with the official TypeScript parser and plugin so ESLint understands types, interfaces, and other TypeScript syntax.
Learn TypeScript on Mimo
Install the core packages
Most projects install ESLint plus the TypeScript parser and plugin:
Bash
npm install --save-dev eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin
If you use Yarn or pnpm, the command changes slightly, but the packages stay the same.
Create an ESLint config file
You can name it .eslintrc.json, .eslintrc.cjs, or eslint.config.js (flat config). A simple .eslintrc.json setup looks like this:
JSON
{
"parser":"@typescript-eslint/parser",
"plugins":["@typescript-eslint"],
"extends":["eslint:recommended","plugin:@typescript-eslint/recommended"],
"env":{
"browser":true,
"node":true,
"es2021":true
},
"rules":{
"@typescript-eslint/no-unused-vars":["error",{"argsIgnorePattern":"^_"}]
}
}
What this does:
parsertells ESLint how to read TypeScript syntaxpluginsadds extra TypeScript-aware rulesextendsloads rule presets so you don’t start from scratchruleslets you override defaults for your team’s preferences
Add a lint script
Add a script to your package.json so linting is one command away:
JSON
{
"scripts":{
"lint":"eslint .",
"lint:fix":"eslint . --fix"
}
}
Now you can run:
Bash
npm run lint
npm run lint:fix
-fixautomatically fixes some problems, like spacing or rule-safe refactors.
Lint only TypeScript files
If you want ESLint to focus on .ts and .tsx files:
JSON
{
"ignorePatterns":["dist/","node_modules/"],
"overrides":[
{
"files":["**/*.ts","**/*.tsx"]
}
]
}
This is helpful in mixed repos where you also have config scripts or generated output.
When to Use ESLint
Linting is useful in almost every TypeScript project, from small apps to large teams. The biggest benefit is that it catches issues early, when fixing them costs almost nothing.
1) Catching bugs that TypeScript won’t flag
TypeScript checks types, but it won’t always catch logic problems or messy patterns.
Examples ESLint can catch:
- unused variables and imports
- accidental fallthrough in
switchstatements - confusing comparisons like
==instead of=== - forgotten
awaitin async code (depending on rules)
2) Keeping code consistent across a team
Code consistency saves time during reviews. Instead of debating formatting and style in every PR, you pick rules once and let the tool be the “bad cop”.
That means fewer comments like:
“Can you rename this variable?”
“Spacing is different in this file.”
“Please remove that unused import.”
3) Making refactors safer
Refactors can turn into whack-a-mole if you miss small issues. ESLint points out broken patterns right away, especially when you move code between files or rename types.
4) Protecting quality in CI
Running lint in CI makes builds fail if someone pushes code that breaks the rule set. That prevents “it works on my machine” moments and keeps the main branch clean.
Examples of ESLint in action
Below are a few common situations where ESLint pays for itself.
Example 1: Catch unused variables and imports
Here’s a file with a few “leftover” items:
import { format }from"date-fns";
const userName ="Amina";
functiongreet(name:string) {
const greeting ="Hi";
return`Hello, ${name}`;
}
console.log(greet(userName));
What ESLint might report:
formatis imported but never usedgreetingis created but never used
After cleanup:
const userName ="Amina";
functiongreet(name:string) {
return`Hello, ${name}`;
}
console.log(greet(userName));
Small issues like this pile up fast in codebases. Linting keeps files tidy without relying on someone noticing during review.
Example 2: Stop “any” from spreading everywhere
In a hurry, someone might write this:
functionprintUser(user:any) {
console.log(user.profile.name.toUpperCase());
}
This compiles, but it’s risky. If user.profile is missing, your app crashes at runtime.
A rule like @typescript-eslint/no-explicit-any warns you early. A safer version uses proper typing:
typeUser = {
profile: {
name:string;
};
};
functionprintUser(user:User) {
console.log(user.profile.name.toUpperCase());
}
When you’re dealing with unknown input, use unknown and validate it instead of using any.
Example 3: Consistent function return types
Some teams like enforcing explicit return types on public functions (especially in libraries):
functionbuildUrl(path:string) {
return`https://example.com/${path}`;
}
That works, but a rule like @typescript-eslint/explicit-function-return-type may require this:
functionbuildUrl(path:string):string {
return`https://example.com/${path}`;
}
This rule is a preference. In many apps, implicit inference is fine. In shared packages, explicit types can make APIs easier to read.
Example 4: Linting React TypeScript files
In .tsx, rules can help you avoid common footguns:
typeProps = {
title:string;
};
exportfunctionCard(props:Props) {
return<h2>{props.title}</h2>;
}
If you enable rules that prefer destructuring, ESLint might suggest:
typeProps = {
title:string;
};
exportfunctionCard({ title }: Props) {
return<h2>{title}</h2>;
}
This one is style-based, but teams often like it because it reduces repetitive props. usage.
Learn More About ESLint
Once basic linting is working, you can level up the setup so it fits your project instead of fighting it.
Common rule sets people start with
These are popular presets for TypeScript projects:
eslint:recommendedplugin:@typescript-eslint/recommendedplugin:@typescript-eslint/recommended-requiring-type-checking(more strict, uses type info)
A solid middle ground usually starts with:
JSON
"extends":["eslint:recommended","plugin:@typescript-eslint/recommended"]
Then you tweak rules only when your team actually feels friction.
Adding type-aware linting (the “strict mode” vibe)
Some rules need access to your tsconfig.json. That’s called type-aware linting.
You enable it by adding:
JSON
{
"parserOptions":{
"project":"./tsconfig.json"
}
}
Now ESLint can catch deeper issues, like promises used incorrectly, unsafe await, or wrong assumptions about types.
Tip: type-aware linting can be slower, so some teams run it only in CI, not on every keystroke.
ESLint + Prettier without drama
Prettier formats code. ESLint checks code quality. They can overlap, so you want them to cooperate.
A common approach is:
Bash
npm install --save-dev prettier eslint-config-prettier
Then add prettier at the end of extends:
JSON
{
"extends":[
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"prettier"
]
}
This turns off ESLint rules that would fight Prettier’s formatting choices.
If you want ESLint to report formatting problems too, you can add:
Bash
npm install --save-dev eslint-plugin-prettier
Then:
JSON
{
"plugins":["@typescript-eslint","prettier"],
"extends":["plugin:prettier/recommended"]
}
That setup makes formatting show up like lint errors, which some teams love and others hate. Your call.
Ignoring files the right way
Linting should skip output folders and vendor files. You can do that with an .eslintignore file:
node_modules/
dist/
build/
coverage/
Or directly inside config:
JSON
{
"ignorePatterns":["node_modules/","dist/","build/"]
}
Running linting before every commit
If you want problems caught before code leaves someone’s laptop, pre-commit hooks are a popular option.
A common stack:
- Husky (git hooks)
- lint-staged (run lint only on changed files)
You’d configure it so only staged .ts and .tsx files get checked, which keeps commits fast.
Editor integration makes it feel “automatic”
The best linting setup is the one you don’t have to think about.
If you use VS Code:
- install the ESLint extension
- turn on “format on save” (if you use Prettier)
- turn on “fix on save” for ESLint if your team likes it
Then warnings show up as you type, like spellcheck for code.
A few rules that often make TypeScript code better
Different teams prefer different rules, but these show up a lot:
-
@typescript-eslint/no-unused-varsStops dead code and unused imports.
-
@typescript-eslint/no-non-null-assertionDiscourages
!when you’re guessing a value exists. -
@typescript-eslint/consistent-type-importsEncourages
import type { ... }for cleaner builds and clarity. -
@typescript-eslint/no-misused-promisesHelps catch async mistakes in callbacks.
A good rule strategy is simple: start small, then tighten rules when you notice the same mistakes repeating.
Summary
ESLint helps you catch bugs and keep TypeScript code consistent by applying rules across your project. Set it up with the TypeScript parser and plugin, add a lint script, and run it locally or in CI.
Once the basics work, you can add type-aware checks, Prettier compatibility, and editor integrations to keep quality high without slowing development down.
Join 35M+ people learning for free on Mimo
4.8 out of 5 across 1M+ reviews
Check us out on Apple AppStore, Google Play Store, and Trustpilot