TypeScript execution environment and REPL for Node.js with source map support
—
Native ECMAScript module support with loader hooks for seamless TypeScript execution in ESM contexts and modern Node.js applications.
Creates ESM loader hooks for TypeScript module resolution and compilation.
/**
* Create ESM loader hooks from an existing ts-node service
* @param tsNodeService - Service instance for TypeScript compilation
* @returns ESM hooks object compatible with Node.js loader API
*/
function createEsmHooks(tsNodeService: Service): NodeLoaderHooksAPI1 & NodeLoaderHooksAPI2;
/**
* Register ts-node and create ESM hooks in one step
* @param opts - Configuration options for registration
* @returns ESM hooks object
*/
function registerAndCreateEsmHooks(opts?: RegisterOptions): NodeLoaderHooksAPI1 & NodeLoaderHooksAPI2;Usage Examples:
import { createEsmHooks, create } from "ts-node";
// Create service and hooks separately
const service = create({
esm: true,
compilerOptions: {
target: "es2020",
module: "esnext",
}
});
const hooks = createEsmHooks(service);
// Or create both in one step
const hooks = registerAndCreateEsmHooks({
esm: true,
compilerOptions: {
target: "es2020",
module: "esnext",
}
});ESM loader hooks compatible with Node.js loader API versions 1 and 2.
/**
* Node.js Loader Hooks API Version 1
*/
interface NodeLoaderHooksAPI1 {
/**
* Resolve module specifier to URL
* @param specifier - Module specifier to resolve
* @param context - Resolution context
* @param defaultResolve - Default Node.js resolve function
* @returns Promise resolving to module URL and format
*/
resolve(
specifier: string,
context: { parentURL?: string; conditions?: string[] },
defaultResolve: Function
): Promise<{ url: string; format?: NodeLoaderHooksFormat }>;
/**
* Get format of resolved module
* @param url - Module URL
* @param context - Format context
* @param defaultGetFormat - Default Node.js getFormat function
* @returns Promise resolving to module format
*/
getFormat(
url: string,
context: object,
defaultGetFormat: Function
): Promise<{ format: NodeLoaderHooksFormat }>;
/**
* Transform source code before execution
* @param source - Source code to transform
* @param context - Transform context including URL and format
* @param defaultTransformSource - Default transform function
* @returns Promise resolving to transformed source
*/
transformSource(
source: string | Buffer,
context: { url: string; format: NodeLoaderHooksFormat },
defaultTransformSource: Function
): Promise<{ source: string | Buffer }>;
}
/**
* Node.js Loader Hooks API Version 2 (Node.js 16.12.0+)
*/
interface NodeLoaderHooksAPI2 {
/**
* Resolve module specifier to URL
* @param specifier - Module specifier to resolve
* @param context - Resolution context
* @param next - Next resolver in chain
* @returns Promise resolving to module URL and format
*/
resolve(
specifier: string,
context: {
conditions: string[];
importAssertions?: object;
parentURL?: string;
},
next: Function
): Promise<{
format?: NodeLoaderHooksFormat;
shortCircuit?: boolean;
url: string;
}>;
/**
* Load and transform module source
* @param url - Module URL to load
* @param context - Load context
* @param next - Next loader in chain
* @returns Promise resolving to loaded module
*/
load(
url: string,
context: {
conditions: string[];
format?: NodeLoaderHooksFormat;
importAssertions?: object;
},
next: Function
): Promise<{
format: NodeLoaderHooksFormat;
shortCircuit?: boolean;
source?: string | Buffer;
}>;
}
/**
* Supported ESM module formats
*/
type NodeLoaderHooksFormat =
| 'builtin'
| 'commonjs'
| 'json'
| 'module'
| 'wasm';Utility for filtering hooks based on Node.js version compatibility.
/**
* Filter ESM hooks by Node.js API version
* @param hooks - Complete hooks object
* @param apiVersion - Target API version (1 or 2)
* @returns Hooks object compatible with specified API version
*/
function filterHooksByAPIVersion(
hooks: NodeLoaderHooksAPI1 & NodeLoaderHooksAPI2,
apiVersion: 1 | 2
): NodeLoaderHooksAPI1 | NodeLoaderHooksAPI2;Usage Examples:
import { createEsmHooks, filterHooksByAPIVersion } from "ts-node";
const service = create({ esm: true });
const allHooks = createEsmHooks(service);
// Filter for Node.js API version 2 (recommended)
const v2Hooks = filterHooksByAPIVersion(allHooks, 2);
// Filter for Node.js API version 1 (legacy)
const v1Hooks = filterHooksByAPIVersion(allHooks, 1);Pre-configured ESM loaders for command-line usage.
// Available as /esm.mjs entry point
export const resolve: NodeLoaderHooksAPI2['resolve'];
export const load: NodeLoaderHooksAPI2['load'];
// Available as /esm/transpile-only.mjs entry point
// Same hooks with transpileOnly: true preset
export const resolve: NodeLoaderHooksAPI2['resolve'];
export const load: NodeLoaderHooksAPI2['load'];Usage Examples:
# Use ts-node ESM loader
node --loader ts-node/esm script.ts
# Use transpile-only ESM loader for faster startup
node --loader ts-node/esm/transpile-only script.ts
# With experimental specifier resolution
node --loader ts-node/esm --experimental-specifier-resolution=node script.tsIsolated ESM loader for child processes.
// Available as /child-loader.mjs entry point
// ESM loader hooks that run in child processes for better isolation
export const resolve: NodeLoaderHooksAPI2['resolve'];
export const load: NodeLoaderHooksAPI2['load'];Usage Examples:
# Use child process loader for isolation
node --loader ts-node/child-loader.mjs script.tsConfiguration options specifically for ESM module handling.
interface ESMCreateOptions extends CreateOptions {
/**
* Enable native ESM support
* @default false
*/
esm?: boolean;
/**
* Experimental specifier resolution mode
* @default undefined
*/
experimentalSpecifierResolution?: 'node' | 'explicit';
/**
* Allow .ts extensions in import specifiers
* @default false
*/
experimentalTsImportSpecifiers?: boolean;
/**
* Module type overrides for specific file patterns
*/
moduleTypes?: ModuleTypes;
}Usage Examples:
import { register } from "ts-node";
// Full ESM configuration
register({
esm: true,
experimentalSpecifierResolution: "node",
experimentalTsImportSpecifiers: true,
compilerOptions: {
target: "es2020",
module: "esnext",
moduleResolution: "node",
allowSyntheticDefaultImports: true,
esModuleInterop: true,
},
moduleTypes: {
"**/*.test.ts": "cjs", // Tests as CommonJS
"src/**/*.ts": "esm", // Source as ESM
}
});import { register } from "ts-node";
// Configure for mixed CJS/ESM project
register({
esm: true,
compilerOptions: {
target: "es2020",
module: "esnext",
moduleResolution: "node",
},
moduleTypes: {
// Legacy components as CommonJS
"src/legacy/**/*.ts": "cjs",
// New components as ESM
"src/modern/**/*.ts": "esm",
// Tests follow package.json type
"**/*.test.ts": "package",
}
});// TypeScript file with dynamic imports
export async function loadModule(moduleName: string) {
const module = await import(moduleName);
return module.default || module;
}
// Works with ts-node ESM loader
const result = await loadModule('./my-typescript-module.ts');import { register } from "ts-node";
// Configure for top-level await in ESM
register({
esm: true,
experimentalReplAwait: true,
compilerOptions: {
target: "es2022", // Required for top-level await
module: "esnext",
}
});// my-esm-script.ts - Can use top-level await
const response = await fetch('https://api.example.com/data');
const data = await response.json();
console.log(data);{
"type": "module",
"scripts": {
"dev": "node --loader ts-node/esm src/index.ts",
"dev:fast": "node --loader ts-node/esm/transpile-only src/index.ts"
},
"ts-node": {
"esm": true,
"experimentalSpecifierResolution": "node",
"compilerOptions": {
"target": "es2020",
"module": "esnext"
}
}
}Install with Tessl CLI
npx tessl i tessl/npm-ts-node