DEV Community

Alex Cloudstar
Alex Cloudstar

Posted on • Originally published at alexcloudstar.com

TypeScript Without a Build Step: Native Type Stripping in Node.js

For years, running TypeScript in Node.js meant picking your poison: ts-node, tsx, esbuild, or setting up a full tsc pipeline. Every new project started with the same ceremony -- install the compiler, configure tsconfig.json, wire up your scripts, and hope nothing breaks.

That era is ending. Node.js v22.6+ ships with native TypeScript support via type stripping, and as of v22 (LTS) it is enabled by default. You can now run .ts files directly.

node index.ts
Enter fullscreen mode Exit fullscreen mode

That is it. No flags, no config, no extra dependencies.


What Is Type Stripping?

Type stripping is exactly what it sounds like: Node.js reads your TypeScript file and strips out all the type annotations before executing it. The types are treated as comments -- they are never checked, just removed.

// What you write
function greet(name: string): string {
  return `Hello, ${name}`;
}

// What Node.js sees
function greet(name) {
  return `Hello, ${name}`;
}
Enter fullscreen mode Exit fullscreen mode

The runtime never sees the types. There is no type checking happening here. The types are there for your editor and your tsc runs -- Node.js just ignores them and executes the JavaScript underneath.


Why This Is a Big Deal

Before this, even simple Node.js scripts in TypeScript required a setup step. If you wanted to write a quick automation script, a CLI tool, or a one-off data migration in TypeScript, you had two options:

  1. Set up a full build pipeline (overkill)
  2. Use ts-node or tsx as a dev dependency (an extra tool to manage)

Now the workflow for TypeScript scripts is identical to plain JavaScript scripts:

# No setup needed
node my-script.ts
Enter fullscreen mode Exit fullscreen mode

This is especially impactful for:

  • CLI tools -- ship a single .ts file and let users run it directly
  • Scripts and automation -- write TypeScript without the overhead
  • Monorepos -- shared scripts no longer need their own build config
  • Quick prototyping -- spin up a new file and run it instantly

What Still Works

Most TypeScript syntax works out of the box with type stripping:

  • Type annotations, interfaces, and type aliases
  • Generics
  • as casts and satisfies
  • Enums (numeric and string)
  • Optional chaining and nullish coalescing
  • import type statements
interface User {
  id: number;
  name: string;
  role: 'admin' | 'user';
}

async function fetchUser(id: number): Promise<User> {
  const res = await fetch(`/api/users/${id}`);
  return res.json() as User;
}
Enter fullscreen mode Exit fullscreen mode

All of the above runs fine with node fetchUser.ts.


What Does Not Work

Type stripping has real limitations. Because Node.js is not running the TypeScript compiler -- just removing types -- certain TypeScript features that emit JavaScript code cannot be supported:

Decorators (legacy)

Old-style decorators (experimentalDecorators: true) are not supported because they require code transformation, not just type removal. Modern Stage 3 decorators work fine.

const enum

const enum inlines values at compile time, which requires the TypeScript compiler to process the entire file. Type stripping cannot do this.

// This will fail with native type stripping
const enum Direction {
  Up,
  Down,
}
Enter fullscreen mode Exit fullscreen mode

Use a regular enum instead -- it works fine.

Namespace imports with complex merging

Some advanced namespace patterns that rely on TypeScript's emit are not supported. Simple namespaces for typing purposes work.


No Type Checking

This is the most important thing to understand: Node.js does not check your types. If you pass a string where a number is expected, your code will still run -- and potentially fail at runtime.

function add(a: number, b: number): number {
  return a + b;
}

add("hello", "world"); // No error from Node.js. Runs. Returns "helloworld".
Enter fullscreen mode Exit fullscreen mode

Type checking is still your responsibility. Run tsc --noEmit separately in CI or as a pre-commit check:

# Check types without emitting files
npx tsc --noEmit
Enter fullscreen mode Exit fullscreen mode

Think of native TypeScript execution as separating two concerns that were always bundled together:

  • Type checking β†’ tsc (you run this for correctness)
  • Execution β†’ node (just runs the code)

When You Still Need a Build Step

Native type stripping is great for scripts, tools, and development. But for production, you still want to build:

  • Bundling for the browser -- browsers do not support type stripping
  • Tree shaking and minification -- you need a bundler for this
  • Targeting older Node.js versions -- type stripping requires v22.6+
  • Performance in production -- pre-compiled JavaScript starts slightly faster than stripping types at runtime
  • Publishing npm packages -- publish .js files, not .ts

For applications, keep your build pipeline. For scripts and internal tools, skip it.


The Practical Workflow in 2026

Here is what a sensible setup looks like today:

// package.json
{
  "scripts": {
    "dev": "node --watch src/index.ts",
    "typecheck": "tsc --noEmit",
    "build": "tsc"
  }
}
Enter fullscreen mode Exit fullscreen mode
  • dev -- runs TypeScript directly with file watching, no compilation
  • typecheck -- validates your types without running the code
  • build -- compiles for production

You get the fast iteration loop of native execution during development, and proper type checking when you actually need it.


Conclusion

Native TypeScript execution in Node.js removes one of the most annoying parts of the JavaScript ecosystem: the mandatory build step for TypeScript scripts. For anything that lives on the server or runs as a tool, you can now write TypeScript and just run it.

The key things to keep in mind: types are stripped, not checked. Run tsc --noEmit for correctness. Avoid const enum and legacy decorators. And for production applications, still build your code.

But for your next utility script? Just write .ts and run it. We earned this one.

Top comments (0)