deno run --check: type-check TypeScript before running it
- tool
- Deno
- command
- deno run
- flag
- --check[=all]
- default
- off for deno run (types are stripped, not checked)
deno run main.ts does not type-check: since Deno 2.0 it strips the TypeScript types and runs the code, even if the types are wrong. deno run --check main.ts runs the TypeScript compiler first and refuses to start when there is a type error, printing TS error codes with the file and line. deno check main.ts does the same check without running anything, which is what CI usually wants.
Without and with --check
count is declared as a number but receives a string:
cat > main.ts <<'EOF'
const count: number = "three";
console.log("running with count =", count);
EOF
echo "--- deno run"
npx --yes deno@2 run main.ts
echo "--- deno run --check"
npx --yes deno@2 run --check main.ts 2>&1; echo "exit: $?"
echo "--- deno check (no run)"
npx --yes deno@2 check main.ts 2>&1 | grep -E "^(TS|error)"Output
--- deno run
running with count = three
--- deno run --check
Check main.ts
TS2322 [ERROR]: Type 'string' is not assignable to type 'number'.
const count: number = "three";
~~~~~
at file:///tmp/work/main.ts:1:7
error: Type checking failed.
info: The program failed type-checking, but it still might work correctly.
hint: Re-run with --no-check to skip type-checking.
exit: 1
--- deno check (no run)
TS2322 [ERROR]: Type 'string' is not assignable to type 'number'.
error: Type checking failed.Without the flag the program runs and prints the wrong value. With --check, nothing of the program runs: the type error is reported and the exit code is non-zero, so a script or CI job stops.
Type checking per subcommand
| Command | Type-checks by default | Flags |
|---|---|---|
| deno run | No | --check, --check=all |
| deno serve | No | --check, --check=all |
| deno eval / deno repl | No | --check |
| deno test | Yes (local modules) | --no-check, --no-check=remote |
| deno bench | Yes (local modules) | --no-check |
| deno compile | Yes (local modules) | --no-check |
| deno check FILE | Only checks, never runs | --all (also remote modules) |
Values of the flag
--checktype-checks local modules, the files of your project.--check=allalso checks remote modules: JSR,npm:packages and URL imports.--no-check(on commands that check by default) skips it;--no-check=remotechecks local files only.
The compiler options come from compilerOptions in deno.json, so strict and the lib settings are the same for deno run --check, deno check and your editor.
In CI and tasks
{
"tasks": {
"dev": "deno run --watch --allow-net main.ts",
"check": "deno check main.ts",
"start": "deno run --check --allow-net main.ts"
}
}A separate deno check step (or deno check **/*.ts) catches errors in every file, while deno run --check only checks the entry point and what it imports. Tasks are explained in deno.json tasks.
Pitfalls
--checkmust come before the script:deno run main.ts --checkpasses--checkto your program inDeno.args.- Type errors inside dependencies are not reported with plain
--check; use--check=allwhen they matter. - Checking adds start-up time on the first run; Deno caches the result, so later runs of unchanged files are faster.
- Bun and Node.js type stripping behave like
deno runwithout the flag: see run a TypeScript file with Bun.
FAQ
Why does deno run execute code with type errors?
Since Deno 2.0, deno run only strips the types and runs the file, the same way bun and Node.js type stripping do, because checking slows every start. Add --check, or run deno check in CI, to get the errors.
Does deno test type-check?
Yes. deno test, deno bench and deno compile check local modules by default, unlike deno run. Pass --no-check to skip it when you only want the tests to run fast.
What does --check=all do?
It also type-checks remote modules from JSR, npm or URLs, not only your local files. It is slower and mostly useful when you suspect a dependency's types; the default --check checks local modules only.