Chapter 1 · Practice 4 of 6
Write erasable TypeScript and mark type-only imports
Why it matters
More tools now run TypeScript by removing the types rather than compiling them. Node.js strips types by default since v22.18.0 and v23.6.0, and the feature is stable from v24.12.0 and v25.2.0. Type stripping replaces type annotations with whitespace. It does not type check, and it cannot handle syntax that generates JavaScript.
Node's docs list what fails under type stripping:
enumdeclarationsnamespaceblocks with runtime code- parameter properties such as
constructor(private db: Db) import x = require()aliasespathsfrom tsconfig, which Node ignores
Two compiler options keep your code compatible:
erasableSyntaxOnlyreports an error for any of the syntax above.verbatimModuleSyntaxrequiresimport typefor imports used only as types, so a stripper never keeps an import of something that does not exist at runtime.
Even if you use a bundler today, erasable code is simpler to move between tools. Replace enums with as const objects or string literal unions, and write constructor assignments out in full.
Do
- Turn on
erasableSyntaxOnlyandverbatimModuleSyntaxin new projects - Use
import typeor inlinetypeimports for anything used only as a type - Replace
enumwith a string literal union or anas constobject
Avoid
- Parameter properties like
constructor(private db: Db)in code Node runs directly - Relying on tsconfig
pathsat runtime: Node ignores them
Example
// Erasable: works with Node type stripping and every bundler
import type { User } from './user.ts';
export const Role = { Admin: 'admin', Member: 'member' } as const;
export type Role = (typeof Role)[keyof typeof Role];
export class UserService {
private readonly users: User[];
constructor(users: User[]) {
this.users = users;
}
}