Using TypeScript with Docker: A Guide to Containerize Your Applications
Yash Chavan
Posted on June 20, 2023
Introduction
Prerequisites
Before we get into using Typescript and Docker together, it is important to understand what these technologies are on their own
Typescript is a programming language that extends JavaScript by adding new features such as type annotations, class and interface definitions, modules, decorators, and more. It's particularly useful for large-scale projects and for developing robust and maintainable code.
Docker is a platform that allows developers to create, deploy, and run applications in containers. Containers are lightweight, portable, and self-sufficient environments that can run on any machine that supports Docker, regardless of the underlying infrastructure, it provides several benefits, including portability, isolation, scalability, automation, and standardization
Understanding these two technologies makes it clear why knowing how to combine the two to build and deploy your applications can be beneficial
Benefits of using TypeScript and Docker
Using Typescript and Docker together gives the clear benefit of having robust and reliable apps but there are several more benefits when building and deploying applications:
Type safety: TypeScript's type annotations can help catch errors early during development, making the code more predictable and easier to understand. This can reduce the number of bugs in the application.
Improved development experience: TypeScript's advanced type system also comes with powerful autocomplete capabilities, providing developers with suggestions for properties, methods, and parameters, making coding faster and more efficient.
Better maintainability: TypeScript's class and interface definitions, modules, and decorators can make the code more organized and reusable, making it easier to maintain and update the application over time.
Consistency and reliability in deployment: Docker allows you to package your application and its dependencies into a single container, which can be easily deployed to any environment. This makes deployment more consistent and reliable and can help to reduce the number of environment-specific bugs.
Scalability: Docker allows for easy scaling of applications by running multiple containers, which can handle increased traffic and workloads.
Portability: Docker containers can be easily moved between different environments, such as development, staging, and production. This ensures consistency and reduces complexity.
Isolation: Docker allows multiple applications or services to run on the same machine without interfering with each other, improving the security and stability of the application.
Improved collaboration: Docker provides a consistent set of tools and technologies that can be used across different environments (So no more, "but it worked on my machine" from your peers), making it easier for developers to collaborate and share their work.
Setting up a TypeScript and Docker project
Let's take an example of a simple Nodejs application to get/create todos in typescript. (make sure you have Node, npm and Docker installed to follow along)
Step 1 - Setting up
To get started open your directory and setup your node app as usual with express.js, or follow the code given below
npm init -y
npm install express body-parser
Step 2- Adding TypeScript
To add Typescript run the following command
npm install --save-dev typescript @types/express nodemon ts-node
This will install typescript as a dev dependency along with types for express, and nodemon which we will use for testing the app locally along with ts-node
TypeScript uses a file called tsconfig.json
to configure the compiler options for a project. Create a tsconfig.json
file in the root of the project directory and paste the following JSON
{
"compilerOptions": {
"module": "commonjs",
"esModuleInterop": true,
"target": "es6",
"moduleResolution": "node",
"sourceMap": true,
"outDir": "build"
},
"lib": ["es2015"]
}
At this point, your directory should look like this
--node_modules/
--package.json
--tsconfig.json
Step 3 - Creating the App
Then create App.ts
file ( you can name it anything you like I prefer App.ts) and paste the code below
import express, { Request, Response } from 'express';
import bodyParser from 'body-parser';
interface Todo {
id: number;
task: string;
completed: boolean;
}
const app = express();
app.use(bodyParser.json());
let todos: Todo[] = [
{id: 1, task: "Take out trash", completed: false},
{id: 2, task: "Do laundry", completed: true}
];
app.get("/", (req: Request, res: Response) => {
res.send("Hello World");
});
app.get('/todos', (req: Request, res: Response) => {
res.send(todos);
});
app.post('/todos', (req: Request, res: Response) => {
const newTodo: Todo = req.body;
todos.push(newTodo);
res.send(newTodo);
});
app.listen(3000, () => {
console.log('Server is running on port 3000');
});
At this point, your directory should be looking like this
--node_modules/
--package.json
--tsconfig.json
--App.js
Step 4 -Time to test the app
To check if the app runs, we already have installed the tools need nodemon which uses ts-node to auto compile and autorun our app with changes, BUT we need to make some changes in our package.json
{
...,
"main": "App.ts",
...,
"scripts":{
"dev": "nodemon",
"start": "node build/App.js",
"build": "tsc --project ./"
},
...
}
dev
is used for testing, while the build
is used to compile our typescript code and start
to run the compiled javascript app.
To start the test server run the following command
npm run dev
Once nodemon finishes you should see the following
$ nodemon
[nodemon] 2.0.20
[nodemon] to restart at any time, enter `rs`
[nodemon] watching path(s): *.*
[nodemon] watching extensions: ts,json
[nodemon] starting `ts-node App.ts`
Server is running on port 3000
Step 5 - Setting up Docker
The next step is to set up Docker, we do that by creating a Dockerfile
and paste the following:
FROM node:14-alpine
WORKDIR /app
COPY . .
RUN npm install
RUN npm run build
EXPOSE 3000
CMD ["npm","run", "start"]
This is the Dockerfile which is the schema to create your docker image,
the COPY
command copies everything in the root directory to the app directory inside the docker image, to avoid us also copying the node modules we need to create a .dockerIgnore
file and add the following inside it,
/node_modules
/build
Now to create the docker image run this command in your terminal:
docker build . -t tsdocker
This will create the docker image
docker run -p 3000:3000 tsdocker
You can open HTTP://Localhost:3000
and get the message Hello World on your screen and there you have it. You have set up your typescript app with docker. We will further how to deploy with a platform like render, in some future blog
Conclusion
Using TypeScript and Docker together can bring many benefits to a Node.js application. TypeScript provides a way to catch bugs early on by providing type checking and interfaces, while Docker allows for easy deployment and scaling of the application by packaging it in a lightweight container. Additionally, Docker provides a consistent environment regardless of the underlying infrastructure, which can prevent issues caused by differences between development and production environments. Furthermore, TypeScript and Docker make it simple to test the application in various environments as well as manage infrastructure and scaling. Finally, they can help to improve the overall development and deployment process by automating the building, testing, and deployment of code changes.
However, we haven't covered all the things, some advanced things you can cover on your own or through my future blogs are using multi-stage build
in Dockerfile
or using docker compose
to run multiple containers.
Posted on June 20, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.