How to Add TypeScript to a Node.JS Server With ts-node

We'll get started with TypeScript in this lesson by installing a few necessary packages in our server and setting up the configuration of our TypeScript compiler.

Project Source Code

Get the project source code below, and follow along with the lesson material.

Download Project Source Code

To set up the project on your local machine, please follow the directions provided in the README.md file. If you run into any issues with running the project source code, then feel free to reach out to the author in the course's Discord channel.

This lesson preview is part of the TinyHouse: A Fullstack React Masterclass with TypeScript and GraphQL course and can be unlocked immediately with a single-time purchase. Already have access to this course? Log in here.

This video is available to students only
Unlock This Course

Get unlimited access to TinyHouse: A Fullstack React Masterclass with TypeScript and GraphQL with a single-time purchase.

Thumbnail for the \newline course TinyHouse: A Fullstack React Masterclass with TypeScript and GraphQL
  • [00:00 - 00:15] To configure our node server into a TypeScript project, we'll need to install certain TypeScript development dependencies. Though there's a few tools that exist, we'll install the latest versions of the TypeScript and TS node libraries.

    [00:16 - 00:40] In our terminal, we'll exit the server for now, clear the terminal console logs , and now simply npm install the TypeScript and TS node packages as development dependencies. TypeScript is a core TypeScript library that will help us compile our Type Script code to valid JavaScript.

    [00:41 - 01:01] TS node is a utility library that can help us run TypeScript programs directly from the terminal. Next, we must create a TS config.json file.

    [01:02 - 01:24] The TS config.json file is a basic JSON file that should be created at the roots of a TypeScript project. This file is where we can customize our TypeScript configuration and guide our TypeScript compiler with options required to compile the project.

    [01:25 - 01:51] To customize and edit our compiler options, the TS config file expects us to specify and declare a compiler options field. There are a large, large number of options we can dictate and control in our compiler, all of which can often be seen in the TypeScript handbook in their main website .

    [01:52 - 02:07] We're not going to go through every different option and the reason behind them , but instead we're going to dictate the ones we need for an app and simply introduce them as we explain it. The first option we'll declare is the target option.

    [02:08 - 02:22] Target allows us to specify the target JavaScript version the compiler will output. Here we'll declare a target output of ES6 since node supports a vast majority of ES6 features.

    [02:23 - 02:33] Next, we'll declare a module option. Module allows us to refer to the module manager to be used in the compiled JavaScript output.

    [02:34 - 02:52] Since CommonJS is the standard in node, we'll state CommonJS as the module option. Next, to specify the location of files of where we want to actually declare TypeScript code, we'll use the root directory option.

    [02:53 - 03:12] We'll give a value of .slashSource, which would essentially tell our compiler that we intend to have all our TypeScript files within the source folder, and with which we want the compiler to actually compile. Next, we'll use the output directory option.

    [03:13 - 03:36] Output directory allows us to specify where we'd want the output of compiled code when we decide to compile our entire TypeScript project into JavaScript. Here we'll specify a new folder that we'll create when this happens called " built" that will be kept at the root of the project directory.

    [03:37 - 03:57] To help compile our CommonJS modules, in compliance with ES6 modules, we'll need to introduce the ES module interrupt option. And give it a value of True.

    [03:58 - 04:18] Finally, we'll be able to apply the strict option, also provide a value of True . Strict allows us to further enable a series of strict type checking options, such as "no implicit any", "no implicit disk", "strick null checks" and so on.

    [04:19 - 04:30] There's a lot more options and configurations we can make, but this is all we'll need for now. Now, if you don't fully understand what's actually happening here, step by step , there's no need to worry.

    [04:31 - 04:52] You're more than welcome to check the TypeScript handbook to get a better understanding of what each of these fields do, but the key takeaway here is the TS config.json file allows us to control the options and configuration of our TypeScript compiler. And most importantly, we're specifying that the root directory of where our files are going to have our TypeScript code is going to live within the source folder.

    [04:53 - 05:11] And then we're applying the strict option, which allows us to apply a series of strict type checking options, dynamically by just specifying this particular field. In our TS config file, VS code is sort of showing a particular error that might be showing up.

    [05:12 - 05:32] Now, this error is most likely attributed to the fact that we don't actually have any TypeScript files within the root directory we've specified our compiler options to actually take into account. Most likely, once we start to introduce our TypeScript files, this error should most likely go away, so we won't pay any attention to it right now.

    [05:33 - 05:43] So now, we're going to look to install the type declaration files for certain dependencies that exist in our app right now. Let's explain this a little more.

    [05:44 - 06:08] For us to use third party libraries, such as Node, Express, etc., and have the full power of TypeScript, those libraries should also have dynamic types. Unfortunately, some of these libraries can are only written in native JavaScript, like Express and Node, or they could also be written in other JavaScript extensions, like CoffeeScript.

    [06:09 - 06:31] This is where TypeScript actually allows us for the creation and use of something known as declaration files, which are simply files that allow us to describe the shape of existing JavaScript code. We could go ahead and create declaration files on our own for Express and Node and any other library you want to use, but that can be pretty tedious and take quite a bit of time.

    [06:32 - 06:47] This is why in the TypeScript community exists a repository known as "Def initely Typed". The "Definitely Typed" repository holds TypeScript declaration files for a large, large number of packages we tend to use and is entirely community driven .

    [06:48 - 07:04] So if you ever find yourself using a package that doesn't have a declaration file publicly available, you're more than welcome to contribute it into this repository. In our application, we're currently using the Express and Node libraries.

    [07:05 - 07:17] These libraries aren't TypeScript libraries, so we'll need to install the Type Script declaration files for these two libraries. We'll install them as development dependencies.

    [07:18 - 07:48] Now to install the declaration files from the "Definitely Typed GitHub" repository, we can install them under the "at types" namespace, which refers to the libraries kept within that particular repository. The very first one we'll install is the "node declaration" file, and the second one we'll install is the "Express declaration" file.

    [07:49 - 08:17] With these packages installed, we can now start to modify our code. The first thing we're going to do is we're going to rename the "index.js" file to be a file denoted by "index.ts". "index.ts" or just "ts" files in general is the file extension used to denote TypeScript files that will eventually be compiled to JavaScript.

    [08:18 - 08:24] Just from that alone, we can see that VS code actually shows us some warnings. We'll get to those in a second.

    [08:25 - 08:54] The first thing we're going to do is instead of using the traditional "requires " syntax, we can now utilize the "import" feature that ES6 provides to import the "Express" module. Though node supports a vast majority of ES6 features, the one thing it doesn't currently natively supports is the "import" syntax.

    [08:55 - 09:09] And this is one advantage of using TypeScript. TypeScript will compile our code to valid ES6 code and node recognizes. So when we actually develop our code with TypeScript, we can take advantage of some pretty new features from JavaScript.

    [09:10 - 09:28] Cool. So now, when we actually hover over this particular warning, we can see that our VS code, it telecents, warns us that the TypeScript compiler would most recognize an error here. It tells us that the Type2 is not assignable to TypeNumber.

    [09:29 - 09:43] This is because it recognizes that when we instantiated the variable to, it was of the "number" type. As a result, we shouldn't be allowed to reassign the value of the variable to a different type.

    [09:44 - 09:54] Just from the simple changes we made alone, we can already take advantage of TypeScript right here already. So with that said, let's actually remove what we've done here.

    [09:55 - 10:04] And let's just keep our variables as numbers for now. The headline feature of TypeScript is static typing.

    [10:05 - 10:19] Instead of having our variables 1 and 2 be inferred as numbers, we can explicitly define the type as "number". To do so, we'll place a colon right after where we actually declare the name of the variable.

    [10:20 - 10:27] And here is where we can specify the type of what we expect these variables to be. In either case, we'll say they should be of type "number".

    [10:28 - 10:42] TypeScript also allows us to apply a number of different primitive types. Assume we had another variable called 3, with which we can specify something like the Boolean type and provide a Boolean value.

    [10:43 - 10:53] We could apply the string type and provide a string value. We could apply the null type and provide a null value.

    [10:54 - 11:04] We could apply the undefined type and pass in an undefined value. And we can even apply the "any" type and specify any value.

    [11:05 - 11:15] There are other basic types as well, such as the array type, the enum type, the void type, etc. We'll investigate a lot of these other different types as we progress through the course.

    [11:16 - 11:28] In any case, when we explicitly define the type of a variable, we have to provide the value that matches that type. This is through initialization or even through reassignment.

    [11:29 - 11:43] For example, for one and two variables, assume for our very first variable we wanted to give it a string value. TypeScript compiler will complain, and the VS code of telecents is smart enough to actually warn us right in our editor.

    [11:44 - 11:55] It basically tells us that the value you're trying to provide doesn't match the type that you specified is variable should be. The only unique type in TypeScript is the "any" type.

    [11:56 - 12:20] "any" allows us to explicitly define a variable with any type, hence the name. Now, these variables don't give us the capability TypeScript provides because we can reassign this particular value to anything that we want. So though it could be used when needed, it should be used sparingly because we don't actually get the power of TypeScript when we use the "any" keyword.

    [12:21 - 12:33] Let's remove this three variable for now. If we take a look at the "tsconfig" file in our project, we can see that warning we saw in our editor doesn't appear any longer.

    [12:34 - 12:44] This satisfies the assumption we made, that warning probably arrived due to the fact that we didn't have any TypeScript files in our project. Cool.

    [12:45 - 12:56] With that said, now let's look to see if we can actually run our application even though we've added TypeScript into our app. Let's take a brief look into the package.json file.

    [12:57 - 13:15] Technically, this start command should work as intended because we intend to run the TypeScript code, i.e. the node TypeScript code within the source folder . However, if we actually run this command currently, it's going to assume to look for a JavaScript file in our source folder.

    [13:16 - 13:30] As a result, we'll look to be a little explicit here and state that we want to run the code in our source.slash index.ts file. With that said, let's head over to the terminal and now run npm run.

    [13:31 - 13:42] And there we have it. Our project now runs despite us doing very minimal changes to actually invoke how we want to run TypeScript code.

    [13:43 - 13:59] In our logs, however, over here, we can see the message "tsnode/index.ts". This tells us that the "tsnode" package in our application is now being used to run the TypeScript app directly from our terminal.

    [14:00 - 14:08] This is in thanks to Nodemon. Nodemon invokes "tsnode" whenever a TypeScript file has been changed.

    [14:09 - 14:22] "tsnode" under the hood does a bunch of checks to verify that all our Type Script code is good and then compiles our TypeScript code to JavaScript. If there's ever a TypeScript error, Nodemon will actually crash.

    [14:23 - 14:32] Let's actually see this. If we intend to make our one number variable, a string, even though we explicitly define it to be a number type.

    [14:33 - 14:48] If we save our file right now, Nodemon will attempt to actually start our server, but it would crash and we would actually see a TypeScript error, stating that it's unable to compile TypeScript. It actually gives us the error where the issue arises.

    [14:49 - 14:53] Let's bring this back to being a number. Let's save it once more time.

    [14:54 - 15:05] Nodemon will restart our server. We can see that our app runs at low close 9000 and now by heading to low close 9000, refreshing what we have, everything should work as intended.

    [15:06 - 15:28] This is a great example of how TypeScript helps to check any errors or issues in our code during compile time, not during runtime. And this was best seen because the moment we specified a string value to a number type, the compiler error even before we attempted to run our application .

    [15:29 - 15:57] Now, though this is a very simple example and you can probably get away without using TypeScript, the importance of TypeScript really comes in for very large scale applications that have multiple developers working together. At any moment in time, if the TypeScript compiler thinks you're doing something wrong, it would warn you most likely in your editor, and then even though it would actually error during compile time, which gives you that very quick feedback.

    [15:58 - 16:26] That's incredibly helpful for developers to move quickly and ensure they're not introducing bugs as they start building more and more features in an application. [ambient sound]