This project contains a little demonstration of How to Typescript your Node app.
If you just want to clone this repository, and run the application, follow these steps.
git clone https://github.com/lucasGabrielDeAA/node-typescript && cd node-typescript
yarn install
yarn tsc
yarn start
Open the browser on localhost:3333 and see the app working, using javascript transpiled from the typescript
Or, if you want to create your own app, you can do this using a simple node app, creating a folder and running some commands, like the following example.
mkdir <yourAppName> && cd <yourAppName>
yarn init -y
To learn how to create a nice node-api with some nice features, take a look at this node-api.
Adding typescript to your app, is really quite simple. just install it as a devDepencency running this command
yarn add -D typescript
Now you can create your .js application's file as .ts files. And make some nice improvents in your code. Like the following example. But let's install some dependencies to make the code's understanding simple.
yarn add express
Then create a index.ts file under your src directory. And in this file we are going to start to type some code.
As you already know, in node's applications we use the require sintax to import libs and applications's dependencies. when you use typescript in your app, you can change the way you import in your .ts files.
// node standard import
const express = require('express');
// node with typescript, import way
import express from 'express';
But what is the difference, is just syntax. Yeah, is just syntax, but when you're a React/react-native software developer as I am. You are already familiarized with the import/export syntax, this will make your learning curve even smaller. Let's continue creating our index.ts file.
import express from 'express';
// application's PORT
const PORT = 3333;
// instantianting our app.
const app = express();
// creating a route
app.get('/', (req, res) => {
return res.send('Hello');
});
// setting the port to the application.
app.listen(PORT);
If you use some IDE features to enchance your code, probably you already know the Ctrl+space (Linux/Windows) Cmd+space (Mac) to auto complete your code. And when you was writing the following line, you probably noted that the IDE didn't understand or found the methods and the functionalities of our app const.
// creating a route
app.get('/', (req, res) => {
return res.send('Hello');
});
This happens because we are using the typescript, and by default, our express's module does not export the type of itself, and the typescript does not recongnize. And to solve this problem you just need to install the types for express, found in this dependency.
yarn add -D @types/express
Now, you can find the inner types and modules of express, in your ts file.
Now we need to run our node application, normally we would do this by running node src/index.js
. But, we don't have a index.js file, and if we run node src/index.ts
we'll find some problems, because node does not understand the syntax on our ts file.
SyntaxError: Cannot use import statement outside a module
To solve this kind of issue, we have to transpile our ts file to a js file, so, node can undertand this file. Let's do this. If you take a look at your node_modules folder, and open the bin's directory, you can find all the scripts you can run in your application. One of them is called tsc. This is the typescript command. We'll use this to transpile our ts files. Let's do this.
yarn tsc src/index.ts
After run this command, the tyoescript will generate a index.js file for you, with the content of your transpiled index.ts file content. But, will show us some error, with a message about the esModuleInterop because we are doing a default import from the express
, to prevent this, go to your index.ts file and change the followinf line.
import * as express from 'express';
Then you run the tsc command again and the error is no more displayed. So now, you can run this command to start your node application.
node src/index.js
Then go to your browser and access localhost:3333 to see the result.
Now we are going further on typescript's configurations to avoid some errors like above, and some other issues. Run this command.
Note: Always remember to delete the index.js file when you need to run the typescript command.
yarn tsc --init
Now you have a typescript's configuration file in the root of your application. Called tsconfig.json. Open it to take a llok in some settings. You will fine a line with this content.
"esModuleInterop": true,
The same information that was shows to us before. Now you can go back to your index.ts file and undo the change on the import.
import express from 'express';
And now to recompile our ts files with the settings of the tsconfig.json we run the typescript command without the file's argument, like this.
yarn tsc
Now, to structure our application, we are going to setting the default's output directory to our application when typescript command runs, open the tsconfig.json and take a look on this line.
"outDir": "./",
Uncomment this and change is to the location you desire. I'll put in a ./dist directory. So let's do this.
"outDir": "./dist",
Now, if you run the typescript command again, you will see the dist's folder with the index.js file on it. And then to restart your application, you just need to change the path from node src/index.js
to node dist/index.js
.
to avoid to always delete our index.js file, re-run the typescript command and re-compile our application using node. We are going to find a solution to make all this process even simple. In standard node applications you can use the nodemon, Babel, or even the sucrase
to do this flux for you. In our typescript environment we are going to use a lib called ts-node-dev
.
yarn add -D ts-node-dev
Then go to your package.json file and create a entry called scripts
with the following content.
"scripts": {
"dev": "ts-node-dev --respawn --transpileOnly src/index.ts"
}
Then you only need to run the following command, to transpile and run your application. And after that, access the application in your browser like before.
yarn dev
And if you made some changes in your file, the td-node-dev
compile your whole application automatically.
First of all, we are going to create a routes's file to our application, called routes.ts in the root of the application, with the following content. Note, the route's file already contains a controller's usage, we are going to create this to.
import { Router } from 'express';
// importing controllers
import UserController from './controllers/UserController';
// creating the routing
const routes = Router();
// declaring routes
routes.get('/users', UserController.index);
export default routes;
Then create the controllers folder under the src, and add the UserController.ts file with this content.
import { Request, Response } from 'express';
const users = [
{name: 'Some name', email: 'someemail@domain.com'},
];
export default {
async index(req: Request, res: Response) {
return res.json(users);
},
};
Note that we are already using types for declaring variables received by the controller. This types comes from the express
because the req and res variable are from the node
IRouterHandler that extends RequestHandler and receive the arguments from the type Request and Response. This is the beginning of typing with typescript. And update our index.ts file to use this content.
import express from 'express';
import routes from './routes';
const PORT = 3333;
const app = express();
app.use(routes);
app.listen(PORT);
Then go to browser and access localhost:3333/users to see the result.
You always need to use some variable or some class created by yourself in your application, son, in this case, you don't have the Types from this information in a library or a decorator's dependency. In this case you have to create the type by hand. Let's do this.
First of all, we are going to create a fictitious mailer service in our application. Create a service folder under the src folder and create a EmailService.ts on it. This file will contains a class used to instantiate our service, and the functionality to send emails.
class EmailService {
send(to, message) {
console.log('Email sent');
}
}
export default EmailService;
The two arguments of the method send need a type. We are going to create this two type using the interface concept. In the EmailService.ts file before the class, add this content.
// interfaces defines our custom types and the type of yours attributes.
interface IMailTo {
name: string,
email: string,
}
interface IMailMessage {
subject: string,
body: string,
attachament?: Array<string>; // The ? operator indicates not-required information.
}
// Data-transfer-object to transfer information between two different files in our application.
interface MessageDTO {
to: IMailTo,
message: IMailMessage
}
// This interface determines the standard model of our EmailService's class.
interface IEmailService {
send(request: MessageDTO): void
}
class EmailService implements IEmailService {
send({ to, message }: MessageDTO) {
console.log(`Email sent to ${to.email}: ${message.subject}`);
}
}
And in our UserController.ts file add a controller to send emails. Remember to add the route to this controller in the routes.ts file.
// UserController.ts
import EmailService from '../services/EmailService';
...
async send(req: Request, res: Response) {
const emailService = new EmailService();
emailService.sendEmail(
{ name: 'Some name', email: 'someemail@domain.com' },
{ subject: 'Welcome to the system', body: 'Be welcome!'}
);
return res.send('OK');
}
...
//routes.ts
...
routes.get('/users/send', UserController.sendEmail);
...
This repository contains only the backend of the full application. Let's do some changes to go forward and create a frontend application using typescript to access this application.
First of all, install the cors
and the @types/cors
to enable our application to receive request from another hosts.
yarn add cors
yarn add @types/cors
In the index.ts file add this lines.
...
import cors from "cors";
...
// adding cors
app.use(cors());
I also added a start script to run the application using js. to do this, add this line on the scripts entry under the dev script on your package.json file.
"start": "node dist/index.js"
And we are ready to go.
To take a look in the frontend application built with react and typescript. click here react-typescript.