You have reached the beginning of time!

Node.js Now Supports TypeScript Natively: Everything You Need to Know

With the release of Node.js v23.6.0, developers can now use TypeScript natively without additional transpilation tools like ts-node or manual compilation steps. This milestone significantly streamlines development workflows, simplifying build processes and improving the overall developer experience by reducing complexity.

Why This Matters

This change goes beyond reducing friction—it minimizes build complexity, eliminates an extra dependency in development environments, and allows for a more seamless experience when working with TypeScript in Node.js. Developers no longer need to set up additional compilation steps, making it easier to focus on writing code rather than configuring build pipelines.

Who Should Read This?

This guide is aimed at developers who are already familiar with Node.js and TypeScript basics. If you’re new to either, consider reviewing the Node.js documentation and TypeScript Handbook before proceeding.

A First Look at the New Feature

Here's a simple TypeScript example (demo.mts) demonstrating native support:

// demo.mts
function main(message: string): void {
  console.log('Message: ' + message);
}
main('Hello!');

Previously, running TypeScript files in Node.js required a transpilation step using the TypeScript compiler (tsc) or a tool like ts-node. Now, we can run the file directly:

node demo.mts # Requires Node.js v23.6.0 or later

For now, running this command will produce the following warning:

ExperimentalWarning: Type Stripping is an experimental feature and might change at any time

Experimental Status and Caution

Because type stripping is still experimental, it is not recommended for production environments yet. Future changes could introduce breaking modifications. To suppress the warning in a development setup, use:

node --disable-warning=ExperimentalWarning demo.mts

For persistent suppression, add it to NODE_OPTIONS:

export NODE_OPTIONS="--disable-warning=ExperimentalWarning"

For long-term configuration, store it in .bashrc, .zshrc, or .env files, or configure it within IDE settings.

Practical Usage: Importing from Popular Libraries

A common real-world scenario is importing a popular Node.js library in TypeScript. For example:

import { writeFileSync } from 'fs';
function saveMessage(message: string): void {
  writeFileSync('message.txt', message);
}
saveMessage('Hello, Node.js!');

This demonstrates how native TypeScript works seamlessly with standard Node.js modules.


Filename Extensions in Node.js TypeScript

Node.js differentiates file types by extensions:

  • .ts: ESM or CommonJS, based on package.json's "type" field.
  • .mts: Always treated as ESM.
  • .cts: Always treated as CommonJS.
  • .tsx: Not currently supported.

Developers must choose filenames carefully to maintain compatibility with Node.js modules. For more details on ESM vs. CommonJS, refer to Node.js documentation.

How Is Node.js TypeScript Different from Traditional TypeScript?

Node.js achieves native TypeScript support through type stripping—removing type annotations without transpilation. Key limitations and workarounds include:

Unsupported TypeScript-Specific Features and Alternatives

Feature Supported? Workaround
Enums ❌ No Use const enum or union types (`type Status = 'success' 'error'`)
Parameter properties ❌ No Declare class properties explicitly in the constructor
Namespaces ❌ No Use ES modules (export {}) instead
JSX (.tsx) ❌ No Use Babel or tsc
Experimental JS Features (decorators, pipeline operators, etc.) ❌ No Wait for native V8 support

Local Imports Require .ts Extensions

// Traditional TypeScript
import { myFunction } from './my-module.js';

// Node.js Native TypeScript
import { myFunction } from './my-module.ts';

Explicit Type Imports Required

import type { Cat, Dog } from './animal.ts';

Recommended tsconfig.json

While Node.js does not read tsconfig.json for execution, it remains crucial for type checking and IDE support. The following minimal setup ensures smooth development:

{
  "compilerOptions": {
    "target": "esnext",
    "module": "nodenext",
    "allowImportingTsExtensions": true,
    "rewriteRelativeImportExtensions": true,
    "verbatimModuleSyntax": true,
    "erasableSyntaxOnly": true
  }
}

Why these settings matter:

  • allowImportingTsExtensions: Allows importing .ts files.
  • rewriteRelativeImportExtensions: Ensures correct TypeScript-to-JavaScript import conversion.
  • verbatimModuleSyntax: Enforces explicit type imports.
  • erasableSyntaxOnly: Prevents using unsupported TypeScript features.

For larger projects, running tsc --noEmit ensures type safety without generating JavaScript files.

The --input-type CLI Option

When running TypeScript code from stdin or using --eval, specify interpretation explicitly with --input-type:

echo 'console.log("Hello" as const)' | node --input-type module-typescript

Type Stripping and Source Maps

Type stripping preserves whitespace for accurate debugging and eliminates source map dependency:

function describeColor(color: Color): string {
  return `Color named "${color.colorName}"`;
}

type Color = { colorName: string };
describeColor({ colorName: 'green' });
Post-type-stripping JavaScript:
function describeColor(color       )         {
  return `Color named "${color.colorName}"`;
}

describeColor({ colorName: 'green' });

What's Next for Node.js TypeScript Support?

A future enhancement, --experimental-transform-types, will introduce full TypeScript transpilation with source map support. This will allow for greater compatibility but remains an opt-in feature.

Type Stripping in Browsers: A Future Possibility?

Could type stripping enable native TypeScript execution in browsers? While theoretically feasible, obstacles such as inconsistent JavaScript engines and performance concerns remain. A timeline for browser adoption is unclear.

Quick Summary Table

Feature Supported Natively Notes
Basic TypeScript Syntax ✅ Yes Type annotations are stripped, preserving JavaScript code
Enums, Namespaces, Parameter Props ❌ No Use workarounds like union types or explicit declarations
JSX (.tsx) ❌ No Requires Babel or tsc
Experimental JS Features (e.g., decorators) ❌ No Supported only when natively available in JavaScript

Conclusion

The addition of native TypeScript support in Node.js v23.6.0 is a significant step forward, simplifying TypeScript workflows and reducing the need for additional tooling. While there are still limitations, future enhancements like --experimental-transform-types may further expand Node.js’s TypeScript capabilities.

Looking to optimize your Node.js applications? NodeSource provides enterprise-grade insights, monitoring, and security solutions tailored for production environments. Explore how N|Solid can help you enhance performance, troubleshoot issues faster, and scale with confidence.

The NodeSource platform offers a high-definition view of the performance, security and behavior of Node.js applications and functions.

Start for Free