How to check typescript errors
Run npx tsc --noEmit in the project root. It type checks every file the tsconfig includes and writes nothing to disk. A clean project prints no lines and exits 0. A project with a defect prints one line per error, with file, line, column and a TS code, and exits 2.
Why check this
This is the check that runs before a pull request merges and again in CI on every push. It is also the first thing to run after a dependency bump, because a new @types package changes the shape of code nobody touched.
The failure it prevents is a build that ships anyway. Most bundlers erase type annotations during transpilation instead of checking them, so a file with a type error can reach the output and fail at runtime. The compiler is the one tool in the chain that reads the types, and --noEmit asks it to read them without producing files.
Prerequisites
- Node 18 or later. This page used Node 22.23.2.
- TypeScript as a dev dependency, so every machine and the CI runner check against one version. The tsc CLI reference lists every flag used here.
- The project below, which is what produced the output on this page. Two files under
src, one file outside it, and a tsconfig withstrictandnoUncheckedIndexedAccesson.
{
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"moduleResolution": "bundler",
"strict": true,
"noUncheckedIndexedAccess": true,
"noEmit": true
},
"include": ["src"]
}
// src/cart.ts
export interface Line {
sku: string;
qty: number;
}
export function firstSku(lines: Line[]): string {
return lines[0].sku;
}
// src/total.ts
import type { Line } from './cart.js';
export function total(lines: Line[], rate: string): number {
return lines.reduce((sum, l) => sum + l.qty, 0) * rate;
}
// legacy/report.ts, outside the include pattern on purpose
export function label(id: number): string {
return id;
}
Steps
- Step 1.
Read the compiler version the project resolves to, not the one on your PATH.
npx tsc --versionVersion 5.9.2Error text and error codes change between minor versions. Record this number with any result you report.
- Step 2.
Type check the whole project and read the exit code.
npx tsc --noEmit --pretty false; echo "exit=$?"src/cart.ts(7,10): error TS2532: Object is possibly 'undefined'. src/total.ts(4,53): error TS2363: The right-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type. exit=2--pretty falsegives one error per line with no colour codes, which is the form a CI log and a grep can both read. - Step 3.
List the files the project actually checks. This is the answer to most "it passes for me" reports.
npx tsc --showConfig{ "compilerOptions": { "target": "es2022", "module": "esnext", "moduleResolution": "bundler", "strict": true, "noUncheckedIndexedAccess": true, "noEmit": true, … }, "files": [ "./src/cart.ts", "./src/total.ts" ], "include": [ "src" ] }filesis the resolved list.legacy/report.tsis not in it, so its obvious defect is invisible to step 2 and always will be. - Step 4.
Check one file by naming it on the command line, and watch the result change.
npx tsc --noEmit src/cart.ts; echo "exit=$?"exit=0The same file errored in step 2. A file path argument makes tsc ignore tsconfig.json completely, so this ran with compiler defaults, where
strictis off. - Step 5.
Separate the two errors by the option that causes one of them.
npx tsc --noEmit --pretty false --noUncheckedIndexedAccess false; echo "exit=$?"src/total.ts(4,53): error TS2363: The right-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type. exit=2lines[0].skuis an error only whilenoUncheckedIndexedAccessis on, because that option gives every index read a| undefined. One flag, and TS2532 is gone.
How to read the result
| What you see | What it means | What to do |
| --- | --- | --- |
| No output, exit 0 | Every file in files type checks | Nothing. Record the tsc version beside the result. |
| error TS2532: Object is possibly 'undefined' | An index or optional read with no guard | Guard it, or narrow with a length check. Do not reach for !. |
| error TS2363 on a number operation | An operand is not a number, often a string from config or a query string | Fix the type at the boundary where the value enters. |
| Errors locally, none in CI | The two runs resolved different tsconfig files or different tsc versions | Compare npx tsc --showConfig and npx tsc --version on both. |
| exit 2 with no error lines | The compiler could not start, usually a missing or malformed tsconfig | Read stderr. Configuration failures use the same exit code as type errors. |
Common mistakes
What to check next
- How to check eslint errors: the other half of the gate, and the one whose exit code lies about warnings.
- How to check prettier formatting: the third command in the same CI job, and the one that fails on files nobody edited.
- How to check installed npm package version: confirms the resolved TypeScript version when two machines disagree.
- How to check node version of a project: a Node mismatch changes which
@types/nodeis in play and with it the error list.
FAQ
How do I check types without building?
npx tsc --noEmit does exactly that. It runs the full program check and writes no .js, no .d.ts and no source maps. The exit code is the result: 0 for clean, 2 for type errors.
Why does my editor show an error that tsc does not?
Usually the file sits outside the include pattern, so the project run never reads it. Run npx tsc --showConfig and look for the path in the files array. If it is absent, widen include or add the directory to a second tsconfig.
What exit code does tsc return?
0 with no errors and 2 with type errors, as step 2 shows. Configuration failures also exit 2. Treat any non-zero status as a failure rather than matching on 1.
How do I check a single file with the project settings?
You cannot do it with a path argument, because that disables tsconfig.json. Keep the project run and filter its output, or point --project at a second tsconfig whose include names only that file.
Should the type check run before or after the tests?
Before. It takes seconds and it fails on code the test run would execute anyway. A failing type check makes most of the test output noise.
Verified
Verified by Maks Vernytsc 5.9.2node 22.23.2
Each output block is what the command above it printed on that date, on the host named in the step. Figures read from a live site move between runs. Compare the shape of the answer rather than the digits, and see the methodology for how a page is re-verified.
Related on this site
basic6 minpublished updated Maks Verny