I have published the repository nodejs-type-stripping
which demonstrates how to implement a package with a bin script that is written directly in TypeScript (no transpilation).
util.parseArgs()
util.styleText()
import pkg from '../package.json' with { type: 'json' };
nodejs-type-stripping/
package.json
tsconfig.json
src/
twice.ts
util_test.ts
util.ts
twice.ts
implements the CLI command.npm install
is only required if you need @types/node
with types for Node.js APIs during editing.
cd nodejs-type-stripping/
node src/twice.ts
Alternative on Unix that hides ExperimentalWarning:
cd nodejs-type-stripping/
chmod u+x src/twice.ts
./src/twice.ts
package.json
This repository only has a single dependency – the types for Node’s APIs:
"devDependencies": {
"@types/node": "^22.13.4"
}
The bin script twice
points directly to TypeScript source code:
"bin": {
"twice": "./src/twice.ts"
}
We need the following property so that .ts
files are interpreted as ESM modules (the rules are the same as for .js
files):
"type": "module"
Package scripts:
"scripts": {
"tsc": "tsc",
"test": "node --test"
}
"noEmit":true
in tsconfig.json
, running tsc
type-checks all TypeScript files in the repository. This package script exists in case I want to install TypeScript locally inside this repository.node --test
finds all *_test.ts
files (among others) and runs them.tsconfig.json
I used the template from my blog post “A guide to tsconfig.json
”.
Important compilerOptions
:
"allowImportingTsExtensions": true,
"erasableSyntaxOnly": true, // TS 5.8+
"noEmit": true,
// Only needed if additionally compiling to JavaScript:
"rewriteRelativeImportExtensions": true,
In Node.js TypeScript code, we use the filename extension .ts
in imports. Hence allowImportingTsExtensions
.
erasableSyntaxOnly
(available since TypeScript 5.8) ensure that we only use TypeScript features that can by stripped – e.g., we can’t use JSX or enums.
I only prevented the emission of files via noEmit
, I did not remove related options such as outDir
– in case I later want to additionally transpile. That is made possible by rewriteRelativeImportExtensions
.
tsconfig.json
” on 2ality.com