Published on

WebSocket with Node.js and TypeScript: Real-Time Communication for Modern Applications

Authors
  • avatar
    Name
    Jonas de Oliveira
    Twitter

In today's web development landscape, real-time communication is a competitive advantage that can significantly enhance user experience. WebSockets allow for bidirectional communication between the client (such as a browser) and the server, enabling continuous data exchange without the overhead of multiple HTTP requests. Integrating WebSockets with Node.js and TypeScript adds robustness and security to your code, making it easier to maintain and scale your applications.

In this article, we will explore the fundamental concepts of WebSockets, explain why you should use them with Node.js and TypeScript, and present a practical example using the ws library.

What are WebSockets?

WebSockets are a communication protocol that enables real-time, full-duplex data exchange between a client and a server. Unlike the traditional HTTP request-response model, WebSockets maintain an open, persistent connection where both the client and the server can send messages at any time.

Advantages of WebSockets:

  • Low Latency: Near-instant communication, ideal for chats, notifications, and online games.
  • Persistent Connection: Keeps the connection open, reducing the overhead of repeated requests.
  • Efficient Data Transfer: Minimal header overhead compared to HTTP, which improves efficiency.

Why Use Node.js and TypeScript?

Node.js

  • High Performance: Well-suited for I/O-intensive and real-time applications.
  • Rich Ecosystem: A vast collection of libraries and frameworks to accelerate development.
  • Event-Driven Architecture: Naturally handles multiple simultaneous connections and real-time communication.

TypeScript

  • Static Typing: Helps catch errors at compile time and improves IDE autocompletion.
  • Maintainability: Produces cleaner and more robust code, making it easier to scale complex projects.
  • Seamless Integration: Works well with Node.js modules and modern development practices.

Practical Example: Implementing a WebSocket Server

We will use the ws library to create a simple WebSocket server with Node.js and TypeScript. The following example is fully commented to explain each step.

1. Project Setup

Create a new Node.js project and install the required dependencies:

mkdir websocket-node-ts
cd websocket-node-ts
npm init -y
npm install ws
npm install --save-dev typescript @types/node @types/ws ts-node

Create a tsconfig.json file for TypeScript configuration:

{
  "compilerOptions": {
    "target": "es6",                  
    "module": "commonjs",             
    "strict": true,                    
    "esModuleInterop": true,           
    "outDir": "./dist"                
  },
  "include": ["src"]
}

2. Implementing the WebSocket Server

Create a folder named src and within it, a file called server.ts with the following content:

// src/server.ts

import WebSocket, { WebSocketServer } from 'ws';

// Define the port on which the WebSocket server will run
const PORT = 8080;

// Create a new WebSocket server instance
const wss = new WebSocketServer({ port: PORT });

// Function to broadcast a message to all connected clients
const broadcastMessage = (message: string) => {
  // Iterate over all connected clients
  wss.clients.forEach(client => {
    // Check if the client's connection is open before sending the message
    if (client.readyState === WebSocket.OPEN) {
      client.send(message);
    }
  });
};

// Event listener for new client connections
wss.on('connection', (ws: WebSocket) => {
  console.log('New client connected.');

  // Send a welcome message to the newly connected client
  ws.send('Welcome to the WebSocket server!');

  // Listen for messages from the client
  ws.on('message', (message: string) => {
    console.log(`Received message: ${message}`);
    // Broadcast the received message to all connected clients
    broadcastMessage(`Client says: ${message}`);
  });

  // Handle client disconnection
  ws.on('close', () => {
    console.log('Client disconnected.');
  });
});

console.log(`WebSocket server running on port ${PORT}`);

3. Running the Server

To compile and run the server, use the following command:

npx ts-node src/server.ts

Your WebSocket server should now be running on port 8080 and ready to accept connections.

Practical Example: Implementing a Simple Client

To test the server, you can create a simple WebSocket client. Create a file named client.html in the project root:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>WebSocket Client</title>
</head>
<body>
  <h1>WebSocket Client</h1>
  <input id="messageInput" type="text" placeholder="Type a message...">
  <button id="sendButton">Send</button>
  <ul id="messages"></ul>

  <script>
    // Establish a connection to the WebSocket server
    const socket = new WebSocket('ws://localhost:8080');

    // Get references to the DOM elements
    const messagesList = document.getElementById('messages');
    const sendButton = document.getElementById('sendButton');
    const messageInput = document.getElementById('messageInput');

    // Display messages received from the server
    socket.onmessage = (event) => {
      const li = document.createElement('li');
      li.textContent = event.data;
      messagesList.appendChild(li);
    };

    // Send a message to the server when the button is clicked
    sendButton.addEventListener('click', () => {
      const message = messageInput.value;
      socket.send(message);
      messageInput.value = ''; // Clear the input field after sending
    });
  </script>
</body>
</html>

Open the client.html file in your browser to test real-time communication with the server.

Final Thoughts

Implementing WebSockets with Node.js and TypeScript is a powerful strategy for creating interactive, real-time applications. By combining the efficiency of the WebSocket protocol with the robustness and security of TypeScript, you can build scalable, high-performance systems ideal for chats, notifications, dashboards, and more.