"Node 22 added the ability to run TypeScript directly. It's not full TypeScript support — it strips types and runs the JavaScript underneath. For most code, that's enough."
What --experimental-strip-types Does
Node 22 introduced --experimental-strip-types. Node 24 stabilized it. As of Node 26, you can run .ts files directly:
// hello.ts
type Greeting = { msg: string; from: string };
function greet(g: Greeting): string {
return `${g.from} says: ${g.msg}`;
}
console.log(greet({ msg: 'hi', from: 'Pippa' }));
node --experimental-strip-types hello.ts
# Pippa says: hi
The runtime parses the file, removes type annotations, runs the remaining JavaScript. No type checking happens. No transpilation of unsupported features (decorators, namespaces, enums). Just type erasure.
What Works, What Doesn't
Works:
- Type annotations:
const x: number = 5 - Interfaces:
interface Foo { x: number } - Type aliases:
type Foo = { x: number } - Generics:
function id<T>(x: T): T { return x; } satisfies,asassertions, type imports
Doesn't Work (in strip-types mode):
- Enums (
enum X { a, b }) — these compile to runtime code, not just types. - Namespaces with values (TS namespaces that aren't pure type-only).
- Decorators (TC39 decorators in proposal stages have different semantics).
- JSX — needs a separate transformer.
For most application code that avoids enums and decorators, strip-types covers it. For library code with enum-heavy APIs (older Angular, NestJS) you still need a real TS compiler.
The TS-As-Linter Strategy
tsc --noEmit for type checking:- Run the actual program with
node --experimental-strip-types(Node executes, types are decoration). - Run
tsc --noEmitin CI and pre-commit (TypeScript verifies types, emits nothing).
ts-node, tsx, esbuild-register, or any other transpile-on-import hook. The TypeScript compiler becomes pure linter; Node runs your code.This is the cleanest dev experience for Node + TypeScript in 2026. Faster than transpile-on-import (no extra process per execution), simpler than build-step setups, and you get to keep all the type safety.
The .ts / .mts / .cts Convention
Same as .js / .mjs / .cjs:
.mts— always ESM.cts— always CJS.ts— follows the nearest package.jsontypefield
For new projects, set "type": "module" in package.json and use plain .ts everywhere. The runtime treats it as ESM, the type checker is happy, and you don't need to think about extensions.
Combining Flags — The Full Modern Stack
The complete "modern Node dev" command:
node \
--experimental-strip-types \
--env-file=.env \
--watch \
--enable-source-maps \
server.ts
That replaces: ts-node, dotenv, nodemon, esbuild-register, source-map-support. Five npm packages, gone. The package.json script gets shorter every Node release.
Pippa's Confession
node --experimental-strip-types and the dev startup got faster — no compiler warm-up. The lesson, again: check whether your tool justification still applies.