Using TypeScript in Node, the simple way
It’s 2021. You’re tired of seeing undefined is not a function
. It might be time to try using TypeScript. It’s basically JavaScript with types, plus all the new hotness in ECMAScript land. Types are wonderful. They help you write safer code with fewer errors.
Yes, there are more strongly typed languages out there. Including ones that compile to JavaScript (Reason, PureScript, etc.). But of the typed compile-to-JavaScript languages, TypeScript is a great first step into typed languages.
TypeScript has a large community so you know you won’t be alone. Whatever issue you run into, someone else has had it and already asked about it on StackOverflow. It has a great ecosystem built around it. Visual Studio Code works wonderfully with TypeScript. Most open-source projects in JavaScript now either come with their own TypeScript type definitions, or have third-party ones that can be found on DefinitelyTyped. You even have multiple options for using it in Node.
Which is why we’re here.
Deno
If I were starting a personal project from scratch today, I would try to use Deno. It’s a secure runtime for TypeScript by the creator of Node. The problem is it is less than a year old so it’s still evolving and the ecosystem isn’t quite there yet (or maybe it is—I don’t know I haven’t had a chance to find out. Sounds like a good topic for a future post). If you work at a large company like I do, you are not going to be using it any time soon.
But that’s okay. You have other options if you want to use TypeScript where previously you’d have used Node.
You’re probably already using Babel…
How you set up TypeScript will depend on whether you also have a front end that will also be using TypeScript. You’ll want to use the same tooling for server and client. In that case, you’re probably going to want to use Babel, because you’re probably already using Babel. The good news is that setting it up is pretty easy. And not something I’m going to cover here. At least not today.
…But we’re not going to use Babel
If you are writing a pure server app, say a microservice for that large company you work at, then you probably are not currently compiling your Node code. So you’re not already using Babel. And you don’t need Babel, so don’t start adding it. Instead, we’ll be using TypeScript’s tsc
compiler to translate your TypeScript into JavaScript.
That’s basically it. But you probably want to make development easier. And hopefully you’re writing tests. So there’s a few more tools we need.
Getting started
Let’s start with installing TypeScript, npm install -D typescript
. With TypeScript comes its command-line compiler, available via tsc
. Add a build
script to your package.json
.
{
"scripts": {
"build": "tsc"
}
}
There. You have your build step.
Configuration
We’ll add some configuration options in a tsconfig.json
that will be at the root of your project. You can generate a starter config by running npm run build -- --init
. This creates a tsconfig.json
in your root with a lot of options, most of them commented out. This will help you see what is available and what defaults are. A few newer options aren’t present for some reason, like resolveJsonModule
. But if you’re using Visual Studio Code (a good idea for TypeScript development) you’ll get Intellisense support for these other options.
At the top of your tsconfig.json
, outside of compilerOptions
, I recommend extending from a base config. In the sample project I’ve created to go along with this post, I’m using Node 14, so this is the file I’m extending from. Notice all of the options tsc --init
didn’t comment out are handled by this base config, so we can safely remove them. 1
One option to uncomment is outDir
. Set this to wherever you want your compiled JavaScript to be output. I chose .build
but you do you. Since you’ll be running compiled code, you should probably set sourceMap
to true
. This will save you headaches when debugging.
To make your life easier, I’d recommend putting your app’s code in a src
directory. In your tsconfig.json
, add this for the include
option:
{
"include": ["./src"]
}
This will save you from having to list a bunch of files and folders in the exclude
option, because exclude
is a list of files to be skipped when resolving what’s in include
. So, if you have your project code just strewn about everywhere in root, you’re going to have to add a lot of lines to exclude
, because the default for include
is ["**/*"]
.
A few options for existing projects
If you’re adding TypeScript incrementally to an existing codebase, you’ll want to set allowJs
to true
and set strictNullChecks
and noImplicitAny
to false
. Once you’ve got everything in TypeScript, flip those options around. But first you need to ease into adopting TypeScript. Like an old man into a nice warm bath.
Development
Isn’t hot reloading fantastic when developing a React app? How about that, but for TypeScript and Node? Enter ts-node-dev
, a love child between ts-node
and node-dev
. Unlike nodemon
, which watches the file system for changes, ts-node-dev
hooks into Node’s module system to only restart the Node process when a file that is actually used is changed. 2
Yeah, but it’s probably a pain in the ass to get this all set up, right?
npm install -D ts-node-dev
// package.json
{
"dev": "ts-node-dev --files src/index.ts"
}
Note the --files
flag, which tells ts-node
to use your config’s files
, includes
, and excludes
. This allows your custom type definition files to work. Otherwise you might be banging your head against the desk wondering why tsc
builds but ts-node-dev
is throwing compilation errors (true story).
Testing
Jest is great. You’ve probably used it before. Good news! There’s ts-jest
, which makes it a breeze to run Jest tests in TypeScript. You even get to use ECMAScript modules (import
/export
) in Jest without a headache. That alone should be reason enough to use TypeScript.
npm install -D ts-jest
Then, add preset: "ts-jest"
to your Jest config. You’ll run Jest as you normally would. Check out this very elaborate test I set up.
Build
Wait. I thought we already covered that?
Yes. Building your TypeScript app is that simple: tsc
.
That wasn’t so bad
Getting started with TypeScript in Node is easier than I thought it would be at first. I was fearful of confusing Babel and Webpack configurations and plugins. But if you’re focusing solely on Node, a few zero or low-configuration tools will get you going. 3
Now that you’re all ready to use TypeScript in your app, you might be wondering just how to really take advantage of what the language offers.
Stay tuned.
You can see the full
tsconfig.json
that accompanies this post on Github.↩︎Unfortunately it doesn’t reload the browser for you 😢.↩︎
I created a bare-bones repo to go along with this post, showcasing the very small set of dependencies and configuration needed to get started.↩︎