My TypeScript Projects are Finally Free from Third Party Loaders
I don't follow the latest trends in the JavaScript ecosystem so imagine my surprise while I was upgrading my projects dependencies, I learned that the latest Node LTS version can now execute native TypeScript code without precompiling to JavaScript or using third-party loaders like tsx or ts-node.
Under the hood, Node is simply stripping away the TypeScript syntax and is not actually compiling the code; therefore, I could not use any features that result in runtime code.
It's a good idea to enable "erasableSyntaxOnly": true in your tsconfig so your IDE will warn you if you tried using any features that results in runtime code
This blog post documents some of the caveats that I found while refactoring my projects to be executable with Node.
No Enums
Unfortunately enums, although useful in many other languages, are not part of JavaScript and thus TypeScript has to generate runtime code to enumulate it.
As a result, I had to refactor all of my enum usage into one of the following workarounds:
No Parameter Properties
This is a nice shortcut when writing classes but there's not much to say other than I had to manually rewrite my classes to be slightly more verbose.
No Path Aliasing
You'd think that Node would try to use my local tsconfig to resolve path aliases but alas it's not possible.
The simplest solution is to just rewrite all of my imports to use relative paths and not use any aliasing. However it's also possible to customize how Node resolves modules thanks to Node's registerHooks function.
Then I can execute my code using this shell command:
Imports Must Include File Extensions
There's also not much to say about this rule other than I had to rewrite all of my TypeScript imports to include the .ts file extension.
It's a good idea to enable "rewriteRelativeImportExtensions": true in your tsconfig so your IDE will warn you if you are missing the file extension
Executing Compiled Code in Electron Projects
In Electron projects with compiled code (e.g. database drivers), the binaries will be compiled against the Node version inside Electron instead of the system's Node version. As a result, callers to the compiled code will also need to be executed using electron instead of node (assuming Electron is also using Node 22.18 or later):
Custom Import Loader
Before migrating my projects to use Node as my TypeScript executor, I was using Bun.js. One of its non-standard features that I made extensive use of was custom import loaders.
Obviously the above code will not be able to run inside Node. Thankfully, I can again use Node's registerHooks function to customize how this "module" is resolved.