How To Use Typescript With HapiJs
In this article, I will attempt to show you how to use typescript with hapi (version 18.4.x). We will clone the API server example on hapi.js’ homepage only that our clone will make use of Typescript. Also i’ll be using yarn
instead of npm
. There’s nothing wrong with using npm so you can use npm if you prefer that.
Before going further, this tutorial is beginner level but I assume that you at least already know what Typescript is and Typescript types. If you don’t, you can read this ‘TypeScript vs. JavaScript’ article. With that out of the way, let’s start.
Create a package.json
This is easy.
yarn init
Add dependencies
This is a hapi server so obviously, hapi is a dependency for this project. Run the command below to add it.
yarn add @hapi/hapi
Development dependencies
Most importantly, we need TypeScript. Also, we need a tool to watch our code and restart our server anytime we make a change. For this, I chose Nodemon. Let’s add the three dependencies to our project. We’ll make use of nodemon later on in the tutorial.
yarn add typescript --dev
yarn add nodemon --dev
Next, we need to install type declarations for both node and hapi. It’s easy as well. Run the commands below
yarn add @types/node --dev
yarn add @types/hapi__hapi --dev
Note: Take care not to install @types/hapi except you are installing hapijs 17.x.
At this point, your package.json
should look similar to this:
{
"name": "hapiserver",
"version": "0.0.1",
"description": "API server",
"main": "index.js",
"author": "Your Name",
"license": "MIT",
"dependencies": {
"hapi": "^18.4.0"
}, "devDependencies": {
"@types/hapi__hapi": "^18.2.6",
"@types/node": "^13.1.1",
"nodemon": "^2.0.2",
"typescript": "^3.7.4"
}
}
Congratulations. We have everything we need but we still need to configure our TypeScript.
Configure TypeScript
Prepare the file structure
In your project’s root directory, create a directory called src.
It will contain all our application’s typescript code. Next, create another directory in the root directory named dist
which will contain all our javascript code compiled from our typescript code.
Note: You can use any file structure you like and name the directories whatever pleases you. This article is just a tutorial to get you going.
At this point, your file structure should look like this
tsconfig.json
Typescript looks for a file named tsconfig.json
to get the specifications of the root file and compiler options required to compile the project. You can learn how to make use of the tsconfig.json file and the available options here.
Add a tsconfig.json
file to your root directory. You can start with something like this:
{ "compilerOptions": {
"outDir": "./dist",
"allowJs": false,
"target": "es6",
"sourceMap": true,
"module": "commonjs",
"moduleResolution": "node",
}, "include": [
"./src/**/*",
], "exclude": [
"node_modules"
],}
Now, let’s test to make sure we haven’t goofed somewhere.
In the tsconfig.json file above, the outDir
option is set to ‘./dist’. This tells the compiler to save compiled files into a directory called ‘dist’. We can test our outDir
is working as follows.
Start by deleting the dist
folder we created.
Next, add an empty file called index.ts
to the src
folder we created.
Finally, in your terminal (make sure you are in the root directory of your project), compile your project with this command
node_modules/typescript/bin/tsc
After it is done, the dist
folder that we deleted should be back. This time around, the dist
folder should also contain the result of our compiled index.ts
file named index.js
.
That’s it. We can now start writing code.
Write The Server (With TypeScript)
Let’s now rewrite the server on hapi’s home page using typescript.
We will use the index.ts
file in our src
directory. It is important that our index.ts
file is located in the src
directory because we have configured typescript to compile only the files in the src
directory.
.ts files are typescript files, .js files are javascript files
Write the code for the server:
index.ts
import { Server, Request, ResponseToolkit } from "@hapi/hapi";const init = async () => {
const server: Server = new Server({
port: 3000,
host: 'localhost'
}); server.route({
method: 'GET',
path: '/',
handler: (request: Request, h: ResponseToolkit) => {
return 'Hello World!';
}
}); await server.start();
console.log('Server running on %s', server.info.uri);
};process.on('unhandledRejection', (err) => {
console.log(err);
process.exit(1);
});init();
Because our code is typescript, we can’t get it to run just yet. We need to compile our source into javascript and run it with node.
Compile typescript to javascript and run (the code)
We already ran the command that makes typescript compile our code to javascript. Every time we change our code, we have to recompile. So run the tsc
command again.
node_modules/typescript/bin/tsc
In the ‘dist’ folder, index.js
should contain our server code. We can now launch the application.
node ./dist/index.js
You should see this output in your terminal:
Server running at: http://localhost:8000
Finishing touches
Instead of manually recompiling source code after every edit, we can make use of npm scripts and nodemon (we installed this as a dependency earlier on) to automate things for us.
Add this to your package.json
{
... "scripts": {
"start": "./node_modules/nodemon/bin/nodemon.js -e ts --exec \"yarn run compile\"",
"compile": "tsc && node ./dist/index.js"
}
}
With this addition, all you have to do is run:
yarn start
What will then happen is nodemon begins to watch your files for changes. If any change is detected, nodemon will run the typescript tsc
command to compile your files and re-launch the application.
If you using windows, nodemon will fail. But the fix is easy. Do the following
Install nodemon globally rather than just for your project. To do this, run this in your terminal. Note that this is also totally valid for other operating systems.
yarn global add nodemon --dev
2. Next, update your package.json’s script field like this:
{
..."scripts": {
"start": nodemon -e ts --exec \"yarn run compile\"",
"compile": "tsc && node ./dist/index.js"
}
}
Done
That’s all. Hapi with Typescript is that easy.