Set Up ESLint for TypeScript
Install and configure ESLint with typescript-eslint to catch bugs and enforce consistent code style in your TypeScript project.
ESLint is a static analysis tool that reads your code and reports problems without running it. The TypeScript compiler catches type errors. ESLint catches a different category of bugs: unused variables, suspicious equality checks, missing await on promises, and patterns that are technically valid but likely wrong.
With the typescript-eslint plugin, ESLint understands TypeScript syntax. It flags issues like using the any type unnecessarily or forgetting to handle promise rejections. For code formatting, pair ESLint with a formatter like Prettier. See Set Up Prettier for TypeScript for that setup.
Install the Packages
Start with a TypeScript project that already has a package.json and tsconfig.json. Install the four required packages:
npm install --save-dev eslint @eslint/js typescript typescript-eslintThe core eslint package is the linter itself. The @eslint/js package provides built-in recommended rules for JavaScript. The typescript package gives the plugin access to the compiler API. And typescript-eslint is the bridge that lets ESLint parse and lint .ts files directly.
Create the Flat Config
ESLint v9 and later use a flat config format in an eslint.config.mjs file. It is simpler than the legacy .eslintrc format and is the only format typescript-eslint recommends for new projects.
Create eslint.config.mjs at the root of your project:
// @ts-check
import js from "@eslint/js";
import tseslint from "typescript-eslint";
export default tseslint.config(
{
files: ["**/*.{ts,js}"],
extends: [js.configs.recommended, tseslint.configs.recommended],
}
);The // @ts-check comment lets TypeScript check the config file itself for mistakes. The files field scopes rules to TypeScript and JavaScript files.
The js.configs.recommended preset enables core rules like banning debugger statements and duplicate imports. The tseslint.configs.recommended preset adds TypeScript-specific rules that flag unnecessary any usage and catch misused promises.
Add a Lint Script
Add a script to your package.json so you can run ESLint with a single command:
{
"scripts": {
"lint": "eslint ."
}
}This adds a lint entry to your npm scripts. Now run it from your terminal to see ESLint in action:
npm run lintWhen you run it, ESLint scans every TypeScript and JavaScript file and reports any problems. If the code is clean, it prints nothing and exits with code 0.
When a problem is found, the output pinpoints the exact file, line number, and rule that triggered:
src/utils.ts
3:7 error 'unusedVar' is assigned a value but never used
@typescript-eslint/no-unused-varsThe error message tells you exactly what is wrong and which rule to look up for an explanation.
Add Stricter Rules
The recommended config is a safe starting point. As your project grows, you will likely want stricter checks. The typescript-eslint plugin provides two additional config layers.
The strict config catches subtler bugs like non-exhaustive checks on discriminated unions. The stylistic config enforces consistent code style: spacing, semicolons, and member ordering. These style rules do not catch bugs, but they keep the codebase looking identical across every contributor.
Add both by extending them in the config:
// @ts-check
import js from "@eslint/js";
import tseslint from "typescript-eslint";
export default tseslint.config({
files: ["**/*.{ts,js}"],
extends: [
js.configs.recommended,
tseslint.configs.recommended,
tseslint.configs.strict,
tseslint.configs.stylistic,
],
});These extra configs are opinionated. If a specific rule does not fit your team, turn it off individually under the rules key in the config object.
Ignore Generated Files
Build output, generated code, and third-party bundles should never be linted. Add an ignores entry to skip them:
// @ts-check
import js from "@eslint/js";
import tseslint from "typescript-eslint";
export default tseslint.config(
{
ignores: ["dist/", "coverage/"],
},
{
files: ["**/*.{ts,js}"],
extends: [js.configs.recommended, tseslint.configs.recommended],
}
);The ignores array uses glob patterns. ESLint automatically skips the node_modules directory by default, so you do not need to list it here.
Run ESLint in CI
Linting is most valuable when it runs on every push and blocks merging if there are violations. In your CI workflow, use the same command with one extra flag:
npx eslint . --max-warnings 0The --max-warnings 0 flag treats warnings as errors, so any warning fails the build. This prevents warnings from piling up over time.
Typed Linting for Deeper Checks
Typed linting uses the TypeScript compiler's type information to run rules that need full type knowledge. It can detect when you call a function that returns a promise but forget to await it, or when you access a property that might be undefined.
Typed linting requires adding a project field to the config pointing to your tsconfig.json. It is powerful but noticeably slower because ESLint must run the full TypeScript compiler on every file.
Start without typed linting. Once your project has a stable type-checking setup and you want deeper scrutiny, add it. For understanding how the TypeScript compiler fits into your overall toolchain, see TypeScript compiler explained.
Rune AI
Key Insights
- Install eslint, @eslint/js, typescript, and typescript-eslint as dev dependencies.
- Use the flat config format with eslint.config.mjs, not the legacy .eslintrc.
- Enable tseslint.configs.recommended for a solid set of TypeScript-aware rules.
- Add a lint script to package.json and run it in CI to prevent regressions.
- Typed linting is powerful but optional; start without it and add it later.
Frequently Asked Questions
Do I need ESLint if I already have the TypeScript compiler?
What is the difference between eslint.config.mjs and .eslintrc?
Should I use typed linting from the start?
Conclusion
ESLint with typescript-eslint gives you a safety net that catches bugs the TypeScript compiler cannot. Install three packages, create one config file, and you have linting that understands TypeScript. Start with the recommended config and add stricter rules as your project grows.
More in this topic
TypeScript Compiler Explained
The TypeScript compiler (tsc) turns .ts files into .js files while checking types. Learn what it does, how to use it, and how it fits your workflow.
Pick Utility Type in TypeScript
Pick creates a new type by selecting only the properties you name from an existing type. Use it to build focused types for specific views, API responses, or function parameters.
Create a tsconfig File
A tsconfig.json file tells TypeScript how to compile your project. Learn how to create one, what the key sections mean, and which options to set first.