Common TypeScript Tooling Mistakes
Avoid the most frequent TypeScript tooling mistakes: missing source maps for debugging, slow CI builds, conflicting ESLint and Prettier configs, and running tsc when you should use tsx.
These TypeScript tooling mistakes are common because they are not obvious until something breaks. A missing flag here, a wrong command there, and suddenly your debugger cannot hit breakpoints, your CI runs for ten minutes, or your linter and formatter fight over every line.
Each mistake below is one you are likely to encounter as your TypeScript project grows. Each fix is small and permanent. Apply them once and your workflow stays smooth.
Mistake: Forgetting Source Maps for Debugging
You set up a launch.json, add breakpoints, and press F5. Nothing happens. The breakpoints turn hollow gray. You spend twenty minutes searching for why the debugger cannot find your code.
The problem is almost always missing source maps.
The VS Code debugger runs your compiled JavaScript, not your TypeScript. Without a .js.map file next to each .js file, the debugger has no way to map the running code back to your original .ts source.
The fix is one line in tsconfig.json:
{
"compilerOptions": {
"sourceMap": true
}
}Enable this before you even try to set up debugging. Rebuild after adding it. Every .ts file will now produce a companion .js.map file, and breakpoints will work. For the full debugging setup, see Debug TypeScript in VS Code.
Mistake: Running Full tsc Builds in Development
You save a file and wait five seconds for tsc --watch to recompile. Then your dev server restarts. Then you notice the typo you need to fix, save again, and wait another five seconds. This is the most common source of frustration in TypeScript projects, and it is avoidable.
The TypeScript compiler is designed for correctness, not speed. During development, you do not need a full type-check on every file change. Your editor already shows type errors inline through the language server. What you need is fast execution.
Replace tsc --watch with tsx --watch for your dev script. tsx strips types with esbuild and starts in under 200 milliseconds. For the comparison between runners, see tsx vs ts-node for Running TypeScript.
Mistake: Forgetting --noEmit in CI
In CI, you run type checking to catch errors before merging. You add tsc to your pipeline and it works, but the build step takes longer than expected.
That is because plain tsc both type-checks and emits JavaScript files. In CI, you rarely need the JavaScript output from a type-check step. You just need to know if there are errors.
Add --noEmit to skip file output:
tsc --noEmitThis runs the full type checker but produces no .js files. Skipping the emit phase saves time, and the amount depends on your project size and how many files change. If your project does need the JavaScript output for a subsequent test step, keep the full tsc build. Otherwise, --noEmit is always the right choice for CI type checking.
Mistake: Letting ESLint and Prettier Fight
You install ESLint and Prettier. Both work. Then you notice that ESLint complains about a formatting choice, you fix it, and Prettier changes it back. You fix it again, and the cycle repeats.
ESLint and Prettier overlap on formatting rules. ESLint has rules about spacing, quotes, and semicolons. Prettier also controls these. When their preferences differ, they fight.
The fix is eslint-config-prettier, a package that turns off every ESLint rule that overlaps with Prettier:
npm install --save-dev eslint-config-prettierAdd it as the last entry in your ESLint config's extends array. It must be last so its rule overrides take priority over everything else. After this, ESLint handles code quality and Prettier handles formatting, with zero overlap. For full setup instructions, see Set Up Prettier for TypeScript.
Mistake: Not Locking Tool Versions
A teammate reports that lint is failing on their machine but passes in CI. After investigation, you discover they have a different version of ESLint installed globally. The rules are slightly different, so their machine catches things CI does not.
Every tool in your TypeScript workflow should be installed as a devDependency with an exact version. This means every machine, every CI runner, and every editor plugin uses the same version of every tool:
npm install --save-dev --save-exact prettierThe --save-exact flag prevents npm from adding a caret range like ^3.9.5. Without it, npm install on a different machine could install a newer minor version that formats differently. Locking versions eliminates this entire category of "works on my machine" bugs.
Mistake: Running TypeScript Without skipLibCheck
You add a library, and suddenly tsc takes twice as long. The library ships a large .d.ts file with complex generic types, and the compiler now checks that entire file on every build. You did not write this code and you cannot fix any errors in it, but you are paying the compile-time cost anyway.
Add skipLibCheck to your tsconfig:
{
"compilerOptions": {
"skipLibCheck": true
}
}This tells the compiler to skip type checking all .d.ts files. Your own .ts files are still fully checked. This single option often cuts compile times in half for projects with many dependencies, and it has no impact on the correctness of your own code.
Mistake: Skipping CI for Tooling Checks
You set up linting, formatting, and type checking locally. They work. But a teammate does not run them before pushing, and broken code reaches the main branch.
Every tooling check that matters should run in CI and block merging. A typical CI pipeline for a TypeScript project looks like this:
{
"scripts": {
"ci": "npm run typecheck && npm run lint && npm run test:run && npm run format:check"
}
}If any step fails, the entire pipeline stops and the merge is blocked. This ensures that no matter what individual developers do on their machines, the main branch always passes every check. For organizing these scripts cleanly, see Use npm Scripts with TypeScript.
Rune AI
Key Insights
- Always enable sourceMap in tsconfig.json before setting up debugging.
- Use tsc --noEmit for type checking in CI, not tsc alone which also emits JS unnecessarily.
- Install eslint-config-prettier to prevent ESLint and Prettier from conflicting.
- Use tsx for running TypeScript scripts and dev servers, not tsc or ts-node.
- Lock tool versions in package.json and run the same commands in CI as locally.
Frequently Asked Questions
Is it really a mistake to run tsc in development?
Should I add .tsbuildinfo to .gitignore?
Can I use both tsc and a bundler like Vite in the same project?
Conclusion
Most TypeScript tooling mistakes come from using the wrong tool for the job: tsc for development when tsx is faster, forgetting source maps and wondering why breakpoints do not work, or letting ESLint and Prettier fight over formatting. Fix each one once and your entire workflow improves.
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.
Set Up ESLint for TypeScript
Install and configure ESLint with typescript-eslint to catch bugs and enforce consistent code style in your TypeScript project.
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.