Creating a Node.js server using TypeScript involves a few straightforward steps. TypeScript, which is a superset of JavaScript, features static types, classes, and interfaces. This makes it a great option when you're building large-scale applications. In this topic, you will learn how to construct a simple Node.js server with the help of TypeScript.
Setting up your project
Firstly, ensure Node.js and npm (Node Package Manager) are installed on your computer. If not, you can download them from the official Node.js website.
Next, create a new directory for your project and navigate into it. Initialize a new Node.js project by executing the following command in your terminal:
npm init -yThen, to install TypeScript, execute the following command in your terminal:
npm install --save-dev typescript @types/nodeThese packages give you the TypeScript compiler and Node.js type definitions, respectively.
Finally, make a tsconfig.json file to manage your TypeScript compilation settings with this command:
npx tsc --initThis command will produce a tsconfig.json file with default settings, which you may need to modify based on your project's requirements.
Writing your server code
Now, create a new index.ts file in your project directory. This file will house your server code.
Then, import in the necessary modules and define the hostname and port:
// Import required modules
import { createServer, IncomingMessage, ServerResponse } from 'http';
import { parse, UrlWithParsedQuery } from 'url';
// Define the server hostname and port
const hostname: string = 'localhost';
const port: number = 3000;The types for these constants: hostname and port are explicitly declared as string and number, respectively.
Next, create a new function type to manage different routes:
type RouteHandler = (req: IncomingMessage, res: ServerResponse) => void;Here, RouteHandler is set to signify the function type for route handlers. Each route handler is a function that takes an IncomingMessage (representing the incoming HTTP request) and a ServerResponse (representing the server's response) and does not return anything (void).
After forming the route handler, define the routes and corresponding operations:
// Define the routes and corresponding operations
const routes: Record<string, RouteHandler> = {
'/': (req: IncomingMessage, res: ServerResponse) => {
// Logic for handling the root route
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
res.end('Hello, World!');
},
'/about': (req: IncomingMessage, res: ServerResponse) => {
// Logic for handling the "/about" route
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
res.end('About page');
},
'/contact': (req: IncomingMessage, res: ServerResponse) => {
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
res.end('Contact page');
},
'/api/data': (req: IncomingMessage, res: ServerResponse) => {
res.statusCode = 200;
res.setHeader('Content-Type', 'application/json');
const data = { message: 'This is some data from the API' };
res.end(JSON.stringify(data));
},
// Handle 404 Not Found
'default': (req: IncomingMessage, res: ServerResponse) => {
res.statusCode = 404;
res.setHeader('Content-Type', 'text/plain');
res.end('404 Not Found');
}
};An object routes is defined to pair route paths to their respective handlers. The type of routes is a TypeScript Record, which is a generic type that stands for an object where all properties have the same type. In this case, all properties of routes are of type RouteHandler.
Having defined the routes, let's now create the server:
// Create the server
const server = createServer((req: IncomingMessage, res: ServerResponse) => {
// Parse the request URL
const parsedUrl: UrlWithParsedQuery = parse(req.url!, true);
const path: string | undefined = parsedUrl.pathname;
// Find the appropriate route handler or use the default handler
const routeHandler: RouteHandler = typeof path !== 'undefined' ? routes[path!] : routes['default'];
routeHandler(req, res);
});The server is created using the createServer function, which accepts a request listener function. This function is invoked for each incoming request, with an IncomingMessage and a ServerResponse.
Inside the request listener function, the incoming request URL is parsed, and the pathname is pulled out. Then, the suitable route handler is found in the routes object using the pathname as the key. If no handler matches the pathname, the default handler is used. The route handler found is then invoked with the request and response objects. The UrlWithParsedQuery type is used for the parsed URL object.
Lastly, call the listen method on the server, providing the port and hostname:
server.listen(port, hostname, () => {
console.log(`Server running at http://${hostname}:${port}/`);
});Compiling and Running Your Server
Before you run the server, compile your TypeScript code into JavaScript using the following command:
npx tscNext, run the server:
node index.jsYou will see the message "Server running at http://localhost:3000/" in your console. If you visit this URL in your browser, you'll see the text "Hello World."
This is what it looks like on the browser:
There you go! You successfully set up a Node.js server using TypeScript. Keep in mind, TypeScript can enhance your code, making it robust and easier to maintain. It is a good choice for larger, complicated projects.
Conclusion
In conclusion, when you create a Node.js server with TypeScript, you ensure type safety by clearly stating the types of variables and function parameters. This lets you catch likely type-related errors during compile time instead of at runtime. As you go on discovering and playing with TypeScript and Node.js, you'll find numerous strategies to use their characteristics effectively in building web applications.