TypeScript WebSockets 101: Getting Started Guide

TypeScript WebSockets 101: Getting Started Guide

Building Real-Time Applications with Type Safety Using WebSockets in TypeScript

What are WebSockets ?

WebSockets provide a full-duplex communication channel over a single TCP connection. WebSockets enable real-time communication between the client and server, making them ideal for applications such as chat apps, live notifications, collaborative tools, etc.

HTTP Polling vs WebSockets

Before WebSockets, real-time communication was often achieved using HTTP polling. This technique involves the client repeatedly sending HTTP requests to the server at regular intervals to check for updates. While effective, polling is inefficient because it generates unnecessary network traffic and latency. WebSockets solve this problem by maintaining an open connection, allowing bidirectional communication without repeated requests.

Backend: Creating a WebSocket Server in TypeScript

Step 1: Install Dependencies

npm install ws
npm install -D typescript @types/ws

Step 2: Create a WebSocket Server

import { WebSocketServer, WebSocket } from "ws";

const wss = new WebSocketServer({ port: 8080 });

wss.on("connection", (ws: WebSocket) => {
    console.log("New client connected");

    ws.on("message", (message: string) => {
        console.log(`Received: ${message}`);
        ws.send(`Server received: ${message}`);
    });

    ws.on("close", () => {
        console.log("Client disconnected");
    });
});

console.log("WebSocket server running on ws://localhost:8080");

Frontend: Creating a WebSocket Client in React / Next.js with TypeScript

//use client; //if using Nextjs
import { useEffect, useState } from "react";

const WebSocketComponent = () => {
    const [messages, setMessages] = useState<string[]>([]);
    const ws = new WebSocket("ws://localhost:8080");

    useEffect(() => {
        ws.onopen = () => {
            console.log("Connected to server");
            ws.send("Hello Server...");
        };
        ws.onmessage = (event) => {
            console.log(`Received from server: ${event.data}`);
            setMessages(prev => [...prev, event.data]);
        };
        ws.onclose = () => {
            console.log("Disconnected from server");
        };
        return () => ws.close(); //Please do not forget this line as clean-ups are important.  
    }, []);

    return (
        <div>
            <h2>WebSocket Messages</h2>
            <ul>
                {messages.map((msg, index) => (
                    <li key={index}>{msg}</li>
                ))}
            </ul>
        </div>
    );
};

export default WebSocketComponent;

Structuring WebSocket Messages with TypeScript (Interfaces)

Remember for more complex applications, always define message types:

interface ChatMessage {
    user: string;
    message: string;
    timestamp: number;
}

Then, we can use this interface in our message handlers:

ws.onmessage = (event) => {
    const data: ChatMessage = JSON.parse(event.data);
    console.log(`${data.user}: ${data.message} at ${new Date(data.timestamp)}`);
};

Handling Multiple Clients

When multiple clients are connected, we can broadcast messages to all clients:

wss.on("connection", (ws) => {
    ws.on("message", (message) => {
        wss.clients.forEach(client => {
            if (client.readyState === WebSocket.OPEN) {
                client.send(message);
            }
        });
    });
});

Conclusion

WebSockets in TypeScript provide a powerful way to build real-time applications with type safety and enhanced tooling support. By structuring WebSocket messages with TypeScript interfaces, we can ensure consistency and reduce runtime errors. Whether you're building a chat app, live dashboard, or multiplayer game, WebSockets combined with TypeScript can offer a seamless and efficient communication mechanism.

And remember, with great power comes great responsibility – so don’t forget to handle disconnections gracefully.