TypeScript Linting: ESLint Flat Config, typescript-eslint and TS 7 (ERESOLVE Fix)
November 6, 2026
Welcome to episode 48 of TypeScript from Zero, a series for complete beginners (no JavaScript needed). Welcome back to TypeScript from zero! tsc finds type errors. A linter finds other problems: code that is legal, but likely to be a bug, or hard to read. The standard tool is ESLint, with a plugin for TypeScript. Today we set it up, and we run into a real surprise on the way. We start in a new file called lint demo.ts. Every code block below is the exact code and output from the video, ready to copy.
- All episodes are in the TypeScript from Zero playlist.
- Versions used: Node.js 26.13.0, npm 11.20.0, TypeScript 7.0.2.
Setup
We start in the terminal and open the project in VS Code:
cd tasks
touch src/lint-demo.ts
code .1. Install
We install ESLint, its recommended rules, and typescript eslint. And npm stops with an error: could not resolve. The reason is in the message: typescript eslint needs a TypeScript version below six point one. We have version seven, the new, fast compiler. The tool does not support it yet, because it needs the old JavaScript API of the compiler.
$ npm install --save-dev eslint @eslint/js typescript-eslint 2>&1 | tail -12
npm error
npm error Could not resolve dependency:
npm error peer typescript@">=4.8.4 <6.1.0" from typescript-eslint@8.72.1
npm error node_modules/typescript-eslint
npm error dev typescript-eslint@"*" from the root project
npm error
npm error Fix the upstream dependency conflict, or retry this command with --force or --legacy-peer-deps to accept an incorrect (and potentially broken) dependency resolution.
npm error
npm error
npm error For a full report see:
npm error /home/mah/.npm/_logs/2026-11-06T10_14_04_215Z-eresolve-report.txt
npm error A complete log of this run can be found in: /home/mah/.npm/_logs/2026-11-06T10_14_04_215Z-debug-0.log2. Side by side
The TypeScript team has an answer: run both versions side by side. The name typescript points to the old version six, which is used only by tools like this one. And the new compiler gets another name, at typescript slash native, which still gives us the tsc command. Now the install works. And tsc is still version seven.
$ npm install --save-dev typescript@npm:@typescript/typescript6 '@typescript/native@npm:typescript@^7.0.2' && npm install --save-dev eslint @eslint/js typescript-eslint && npx tsc -v
added 2 packages, changed 1 package, and audited 47 packages in 2s
13 packages are looking for funding
run `npm fund` for details
found 0 vulnerabilities
added 91 packages, and audited 138 packages in 43s
41 packages are looking for funding
run `npm fund` for details
10 moderate severity vulnerabilities
To address all issues (including breaking changes), run:
npm audit fix --force
Run `npm audit` for details.
Version 7.0.23. Config
ESLint reads a flat config file, a normal JavaScript module that exports a list. We take the basic recommended rules, and the type checked rules of typescript eslint. And one setting: project service true, which lets the rules ask the compiler about types. That is what makes the rules smart.
4. Bad code
Now a file with two habits to avoid. A variable of type any, which switches the checks off. And a call to an async function without await, a floating promise: if it fails, nobody will ever know. We run ESLint on the file. It reports the any, the unsafe use of it, and the promise that must be awaited. That last rule needs types: ESLint has to know that main returns a promise.
eslint.config.mjs:
import eslint from "@eslint/js";
import tseslint from "typescript-eslint";
export default tseslint.config(
eslint.configs.recommended,
tseslint.configs.recommendedTypeChecked,
{
languageOptions: {
parserOptions: { projectService: true, tsconfigRootDir: import.meta.dirname },
},
},
);src/lint-demo.ts:
import { loadTasks } from "./store.ts";
async function main() {
const data: any = await loadTasks();
console.log(data.length);
}
main();$ npx eslint src/lint-demo.ts
/home/mah/tasks/src/lint-demo.ts
4:15 error Unexpected any. Specify a different type @typescript-eslint/no-explicit-any
5:20 error Unsafe member access .length on an `any` value @typescript-eslint/no-unsafe-member-access
7:1 error Promises must be awaited, end with a call to .catch, end with a call to .then with a rejection handler or be explicitly marked as ignored with the `void` operator @typescript-eslint/no-floating-promises
โ 3 problems (3 errors, 0 warnings)5. Fix
We remove the any, so the type comes from load tasks, and we put the await in front of main. ESLint is quiet, and so is tsc.
src/lint-demo.ts:
import { loadTasks } from "./store.ts";
async function main() {
const data = await loadTasks();
console.log(data.length);
}
await main();$ npx eslint src/lint-demo.ts$ npx tsc --noEmit$ npx eslint src/lint-demo.ts && npx tsc --noEmitRecap
Today: ESLint with the flat config, typescript eslint with type checked rules, the floating promise rule, and the workaround for TypeScript seven: the old version under the name typescript, and the new one as native. Next episode: project references.