January 17th, 2025 × #nodejs#typescript#deno
Node + TypeScript in 2025
Discussion on running TypeScript code in Node.js without needing compilation, now that Node supports type stripping. Covers limitations, tools like TSX and Deno, and the much smoother developer experience working with TypeScript.
- Discussion on running TypeScript in Node
- Deno runs TypeScript without needing a TS config
- TypeScript adds type information to JavaScript which engines don't understand, so it needs to be compiled or have types stripped
- Node can now run TS files without intermediaries by stripping types
- Enums in TS should be avoided because they cross from description to actual code
- Avoid TS features like enums and parameter properties that need compilation
- Need to import types with the type keyword when stripping types in Node
- TSX allows running TS in Node without needing compilation
- Deno and BUN have great TS and JSX support since TS is a first-class citizen
- Less obstacles to using TS now across tools
Transcript
Scott Tolinski
Welcome to Syntax on this Monday, hasty treat.
Scott Tolinski
We're gonna be talking about Node and TypeScript, or should I say TypeScript in Node.
Scott Tolinski
How can you use TypeScript with Node? Are there various ways with the new stuff? Yeah. There's a lot here. So my name is Scott Tolinski. I'm a developer from Denver. With me JS always is Wes Bos. What's up?
Wes Bos
Hey. Excited about TypeScript being much easier in Node now. So we're gonna explain Scott what that means and and what the downsides and upsides are to this JS well as a bunch of other tools, and we'll, of course, talk about Deno and Bun as well. The implications, if you will.
Scott Tolinski
The implications, though, of you writing code are that it's going to break.
Scott Tolinski
And if your code breaks, well, you need a tool like Sentry on your side to help you fix it. But more than just breaking, if your code is slow, maybe your Node stinky. Who knows? Sanity will help with most of those things. It will not help if your your code is physically stinky. If it if there's code smell, it might help there. But if you want to check it out, head on over to century.ioforward/ syntax. Sign in to get 2 months for free with the coupon code Sanity treat and make better stuff. I mean, that's really the end all be all of it JS that century just really helps you, enables you to make better stuff all the time.
Scott Tolinski
So
Wes Bos
check it out.
Scott Tolinski
So you want to run TypeScript in Node.
Discussion on running TypeScript in Node
Scott Tolinski
What do you do? Do you fire up TSC, create a TS config and compile down every time you make a change? What do you do, Wes? Yes. So Node a couple months ago, rolled out experimental
Wes Bos
type stripping support And in Node 23.6, so just at the time you're listening, a couple weeks ago, they unflagged that, meaning that TypeScript can be run-in Node without a flag right now. It's still considered experimental, but we're gonna talk about what that means and whatnot. But this is this is pretty huge because it means a whole class of tools and how we write TypeScript may be going away, which is is pretty exciting that it's gonna be sort of a first class citizen.
Scott Tolinski
It's very exciting. Yes. Yeah. Especially because I don't know about you, but the t s config to me, as far as configs go, it's one of those ones where, like, I just tweak it until it works or until it does what I warp it to do. I'm not, like, fully versed on every single op. There JS too many options and too much variety. They do too many different things. If I don't have to get into my t s config to run TypeScript code and, you know, not have to deal with that compilation step, then Yeah. Yeah. I'm gonna do that. Yeah. Deno
Wes Bos
actually runs TypeScript as well with not have needing a TS config, which is really nice when you just wanna do something very quickly. I still recommend you have a TS config for most of your projects because there's lots of good stuff in there in terms of both how it's compiled as well as different rules for your editor.
Deno runs TypeScript without needing a TS config
Wes Bos
So let's start with a refresher.
TypeScript adds type information to JavaScript which engines don't understand, so it needs to be compiled or have types stripped
Wes Bos
TypeScript is JavaScript with some type information sprinkled on top. So, basically, you're just adding information about the shape of your functions and your objects and your data and how things can be passed to each other. And JavaScript engines don't understand TypeScript. They understand JavaScript. So in order for a JavaScript engine, whether that is your browser with, like, a VA in Chrome or, JavaScript core, which is what runs in Safari in BUN, before it can run that, it has to either do 1 of 2 things. It has to compile your TypeScript into JavaScript, or it has to strip the types out of your TypeScript so that it will be JavaScript.
Wes Bos
So the difference between those 2 is that stripping types does not do any type checking.
Wes Bos
It will simply take your TypeScript, and it will find the parts where you added types, and it will simply just take them out. In the case of Node. Js, it literally replaces them with white space so that the source maps still are reflected. There's no there there is no source maps because your TypeScript is essentially just you they just punch out all the holes of where, those pieces are. Compiling TypeScript is a little bit different in that. Once you have that TS config file, you can tell TypeScript several things in terms of how should it output it. Should it output it as common JS? Should it output it as, as ESM? Should it polyfill some of the features that are not available? Other things it will do is what should it do with JSX that it encounters? Should it compile it to React JSX? Should it leave it alone? Should it compile it to Preact? There's a couple options that you have there. So the Node JS implementation currently of TypeScript is simply type stripping, meaning that it does not do any transformation of your code other than simply just punching out the types and replacing them with white space.
Wes Bos
So that's exciting because Yeah. A, you can now just run node something dotts, and it will just run that code without any intermediaries.
Node can now run TS files without intermediaries by stripping types
Wes Bos
The sort of limitations of that right now is because it's not compiling your or transforming your TypeScript, you cannot use any of the features of TypeScript that transform what your code actually looks like. So the big ones there being enums. So enums are kind of a weird one in TypeScript in where it's a a type. It's a way to specify possible options. So you might have, like, an pnpm for, status, you know, pending, private, published.
Wes Bos
Those convert to objects in TypeScript, and it's a bit of a weird thing. A lot of people, myself included, just say don't use don't use enums at all, because they sort of cross the boundary of from description
Enums in TS should be avoided because they cross from description to actual code
Scott Tolinski
to actual JavaScript code. Right. It's actually being used as code. It is not a landmark. It is not a type even though it is being used that way. I I was for a while until I had that realization that if we are stripping the types from a file, then, of course, that means that's not real code. Right? You cannot use that. So that's really what took me on about it. You know, I. People might be wondering if not enums, what do you use? Well, largely string literals warp are one thing that is or even just,
Wes Bos
options in general objects. Right? Yeah. Just an object or a map is it it compiles to an object. If you if you write an pnpm, compile it, it's an object at the end of the day with a bunch of keys on it, and those keys can also have values if if you want that. So you can if if that's the case, that's just that's just a dictionary lookup. Right? And that can be an object or a map in most cases, and that's often what I'll reach for. And now that we have as const too, you can throw an as const
Scott Tolinski
on the end of that object
Wes Bos
and make that pretty explicit. Yeah. Generate a quickly generate a type for it or get a union of all the keys if you want. So, yeah, it's it's totally doable. Even, like, Deno will say, like, they have this thing called fast types, and there's, like, rules of things you should not use.
Wes Bos
And enums is is one of those. And, plus, we also now have a there's a proposal for adding type stripping to the JavaScript syntax, meaning that, we eventually will I bet we'll have this idea where you can just run TypeScript files in the browser as well, and then the the JavaScript browser engine will also know how to strip types out. So if you're thinking about, like, future compatibility of what this looks like, try to avoid features that, need to be compiled before they can be used. So enums is probably the big Node, namespace, legacy module, and parameter properties is also another really big one. So parameter properties in TypeScript allow you to, initialize a class property in the constructor rather than having in your class rather than having to specify the property inside of the class. Okay. Because, otherwise, what you're doing when you construct a class, your constructor is full of these, this Scott name equals name, this dot age equals age, etcetera, etcetera. And you have all these, like, annoying settings. So TypeScript allows you to set both whether it's a public or private property as well as the type directly in the constructor. And then when you pass the value, it'll immediately get set on the class.
Wes Bos
Interesting. Yeah. Yeah. That's that's probably the one that I'm a bit bump. But I'm I'm gonna say, there also is work being done on Node. Js, called experimental transform types. So it's not that this will be this way forever, but they are working on the loader so that you will be able to use all of these features in your Node. Js, which is is great because, like, if we have this thing where it's like, oh, great. We have it, but you can't use any of these features. It's always a bit of a bummer, and then people just go and use the other the features. You know? Like, it's don't make it, like like, watered down. Give us all the features because at the end of the day, people are going to need these features.
Need to import types with the type keyword when stripping types in Node
Wes Bos
Yes. The other kinda gotcha is and we've talked about this in the past, is you have to import types with the type keyword.
Wes Bos
And I've I think I've on the gone on the podcast saying I've I don't see any reason why you would need to use the type keyword.
Wes Bos
And the way that this works is if you're importing a type from a file, you can just import it just like you're importing any other export that's a variable or a function.
Wes Bos
But the other way to do it in TypeScript is you say import type podcast, and that's the the type of podcast. So if you want to use this with Node. Js, you have to use the type keyword.
Scott Tolinski
I've always used the type keyword. And from my perspective, especially if you are having types that cross the server client boundary, that's when I've gotten into issues where server code is leaking into my client code
Wes Bos
without using the type annotation there in the import. So I've always used it. So I've I've always been in the case that don't use it, but I have been confused a few times when I'm importing something with a capital on it.
Wes Bos
Is that a class, or is that a type, or is it both? So explicit. I like it. Yeah. Yeah. Yeah. I can I I could see that? So that's the sort of upsides and downsides to Node. Js. There's no need for source maps.
Wes Bos
Part of why I kind of like this whole type stripping is you're not introducing a a build step in the middle.
Wes Bos
The code you write is the code that is run pretty much.
Wes Bos
There's no need for source maps, so you're not getting some weird stack traces that don't make sense to you at all.
Wes Bos
One thing is they have on the website is they say it's not for dependencies.
Wes Bos
So to discourage package authors from publishing packages written in TypeScript Mhmm. Node will, by default, refuse to handle TypeScript files inside of folders under a Node modules path. Sense. Yeah.
Wes Bos
I kind of, but, also, I'm so sick of having to debug compiled JavaScript where I was all this babble crap and all these like, it's compiled to e s five, and, like, I just wanna I wanna run the code as it was authored. And I know that might be a pipe dream that will never hit, but wouldn't it be nice? Oh, yeah. No. I, a 100% agree with you. I would just be
Scott Tolinski
concerned for, you know, people on older versions of Node. They install something. I guess you'd you'd also publish the compiled versions as Wes. And then, you know, if you're in TypeScript environment publishing
Wes Bos
Yeah. The TypeScript, the ESM, the common JS, the types.
Scott Tolinski
Trust me. It my dream would just be, you you just use the file that's authored, and it just imports and works. And there's no compilation. Yeah. That's that's my dream as well. But,
Wes Bos
again, it's it's not a standard, so we get it.
Wes Bos
Because, like, what happens when we move on from TypeScript What? And we want the new Vercel. You know? What? So Yeah. Yeah.
Wes Bos
We'll see about that other tool. So that's Node. Node 23, You can start using it today. Obviously, it's still experimental. It's gonna throw a a little warning in your console when you run it. I think in in a couple months or whatever, we'll start to see, especially once the transformation part comes. If you're not using that, if you wanna like I I personally have a Node. Js TypeScript course platform. I use TSX.
TSX allows running TS in Node without needing compilation
Wes Bos
So TSX is not the same thing as TSX, which is for JSX ESLint TypeScript.
Wes Bos
TSX means TypeScript execute, and you can use it in place of Node, meaning that you just say t s x your app dot t s, and it will do the transpilation and everything for you. And in my experience, this works flawlessly. I don't even when I deploy my code to production, I don't even compile it. I simply just run TSX in production, and it it runs it. And it works really well. It passes all the like, one thing about using, like, nodemon and and all these other tools is you have to figure out how do you pass all these arguments to the node process. Mhmm. TSX does a fantastic job of passing the command line flags that are not for it just to the node process that is Node. So big fan of that. Yeah. Have you used any others?
Scott Tolinski
Yeah. I've used t s Node, which JS, a fairly popular one for basically doing exactly, just running TypeScript as nodes. Way more popular than TSX, like, 5 times more popular. That's the only one that I've used.
Scott Tolinski
I've also done straight up JS doc style typing where you're writing comments for your types instead of writing dotts files, you're writing Scott JS files.
Scott Tolinski
I think JS doc is a very, very, reasonable solution to some of this stuff. Totally. That said, I still mostly opt to writing .ts files 99% of the time.
Wes Bos
JSDoc is awesome.
Wes Bos
If you have an app that's not in TypeScript, you can just start writing JSDoc because Versus Node will still consume Yes. Like, a a lot of people don't know this, but Versus Code is built on top of TypeScript. That's that's why Versus Code is so good at JavaScript because it it's still even if you have a JavaScript project, it still runs everything through the TypeScript with allow JS turned on. And if you just start adding JSDoc to a lot of your functions, you know, all of a sudden, you have some nice types. And that's a great way to sort of move to TypeScript without having to do a big rename of all your files. And I I'm gonna be honest. I like
Scott Tolinski
j s doc for more than just the TypeScript features. I like that you can, like, mark functions as deprecated and, give a little context to things here and there, write a description. I Type an error. You you cannot one thing TypeScript can't do is you can't type what a function throws. So Yeah. You have no idea
Wes Bos
what once you catch an error from a function, you have no idea what the shape of that thing is, and you have to sort of narrow it down inside of TypeScript. I really wish you could do that. You also can't type an entire function Yes. Straight yeah. Where with JS doc, you can type the inputs and outputs of a function with 1 1 fell swoop, which is nice. Yeah. You're right. Let's talk about Deno and BUN. So Deno and BUN obviously have TypeScript built in as a first class citizen and, I think, are largely responsible for Node getting this, which is really exciting.
Wes Bos
And Deno and BUND's implementation are really good. They also have JSX support, which is something that Node will not do with TypeScript. Because when you have JSX, TypeScript needs to understand what to do with it.
Deno and BUN have great TS and JSX support since TS is a first-class citizen
Wes Bos
And you can like I said earlier, you can tell it to compile it to React. You can tell it to compile to Preact. You can tell it to leave it alone. There's a bunch of different options there. So do you know when BUN having JSX built in as a 1st class citizen is really nice, especially if you're just trying to mock up some templates real quick? I love it. Yeah. Yeah. And then just like BUN has a whole bunch of nice niceties around JSX and TypeScript for logging, and displaying your your components and whatnot. Word. Well,
Scott Tolinski
do you have anything else here? Because I love where we're at with this world compared to where we were at 5 years ago, even 2 years ago, 1 year ago in TypeScript.
Scott Tolinski
It does feel like there are less foot guns. There's less in the way of just getting going. And to me, that's great for all accounts. Totally. Yeah. It's it's not like a thing anymore where you need to, like, literally
Less obstacles to using TS now across tools
Wes Bos
run a Webpack watcher and compile, and then your node process watches the output and restarts itself. And, thankfully, that stuff is is a thing of the past, and every single tool I've used in the last year or 2, just TypeScript first class support.
Wes Bos
Right. Alright. That's it for today. Thanks for tuning in. We will catch you later. Peace.