All articles
EngineeringFeb 1, 20268 min read

TypeScript generics that make your APIs self-documenting

How I use generics, discriminated unions, and branded types to turn a TypeScript API layer into documentation that can't go stale.

01

Comments rot, types don't

A comment saying 'id must be a valid UUID' is a suggestion. A branded type is a guarantee. On every TypeScript codebase I ship now, primitive-obsessed fields — user IDs, email addresses, currency amounts — get wrapped in branded types so the compiler rejects a raw string where a validated one is required.

This single change eliminates an entire category of bugs: passing an order ID where a customer ID was expected, or a dollar amount where cents were expected. The type system becomes the documentation, and it's impossible for it to go out of sync with the code.

02

Discriminated unions instead of optional-field soup

A response shape with five optional fields that 'depend on status' is a runtime bug waiting to happen. I model API responses as discriminated unions keyed on a `status` or `type` literal, so TypeScript narrows the shape automatically inside every `if` or `switch` branch.

  • Every union member has only the fields that are actually valid for that state
  • Exhaustiveness checks (`never` in the default case) catch missing branches at compile time
  • Frontend and backend can share the same union types via a shared package
  • This turns 'what fields exist when status is pending?' into a question the compiler answers for you
03

Generic repository and service layers

Instead of writing a near-identical CRUD service for every Mongoose or Prisma model, I write one generic `Repository<T>` with typed `find`, `create`, and `update` methods. Model-specific services extend it and add only the domain logic that's actually unique.

The payoff compounds: adding a new entity to the system means writing a schema and a thin service, not 200 lines of boilerplate. Refactors that touch every repository become one generic-type change instead of a search-and-replace across dozens of files.

04

Inference-friendly function signatures

Generics are only useful if callers never have to write them out by hand. I design functions so TypeScript infers the generic parameter from the arguments — a validation function that takes a Zod schema, for example, infers its return type from that schema automatically.

The test I apply to every exported function: can someone call it with sensible arguments and get full autocomplete on the result, without ever typing an angle bracket? If not, the generic is designed wrong.

05

Where strict typing stops paying off

Not everything needs a branded type or a five-level generic. Internal one-off scripts, quick prototypes, and glue code between well-typed layers are fine as plain types. Over-engineering the type layer slows down iteration without preventing any bugs that would actually occur.

The rule I follow: invest in types at trust boundaries — API inputs, database reads, third-party responses — where invalid data actually enters the system. Everywhere else, keep it simple.


Written by

Tariq Mehmood

Full Stack MERN Developer

Work with me

Keep reading

Artificial Intelligence

Will AI Replace Developers in 2026? The Truth About the Future of Software Development

AI can now write code, debug applications, work across repositories, and handle complex development tasks. But will AI actually replace software developers? Here is what is really changing in software development in 2026.

Artificial Intelligence

AI Coding Agents in 2026: From Copilot to Autonomous Software Development

AI coding has moved beyond autocomplete. In 2026, developers are increasingly using agents to plan tasks, modify repositories, run tests, debug failures, and complete multi-step engineering work.

Cybersecurity

AI-Generated Code Security: How Developers Can Stay Safe in 2026

AI can accelerate development, but generated code can introduce security vulnerabilities. Learn how to build a safer AI-assisted development workflow with testing, code review, scanning, and human oversight.

Web Development

SvelteKit 3 vs Next.js in 2026: What Should Developers Choose?

SvelteKit 3 is challenging the dominant React framework approach with a simpler architecture and new RPC capabilities. Here is how SvelteKit and Next.js compare for modern web development.

Performance

Next.js 16.3 Performance Optimization Guide for 2026

A practical Next.js 16.3 performance guide covering Instant Navigations, Partial Prefetching, Server Components, caching, JavaScript delivery, and Core Web Vitals.

Engineering

AI Productivity in Software Engineering: How to Measure the Real Impact in 2026

AI adoption is widespread across software teams, but adoption alone does not prove productivity. Learn which engineering metrics can reveal whether AI is actually improving development.

React

React Performance in 2026: What Developers Should Actually Optimize

React performance optimization is changing with React Compiler, modern rendering patterns, Server Components, and better browser tooling. Here is what still matters.

Architecture

Modern Full-Stack JavaScript Architecture in 2026

Full-stack JavaScript applications are evolving around server rendering, API-driven systems, AI integrations, typed code, caching, and cloud deployment. Here is a practical architecture guide.

AI Engineering

MCP and AI Agents: Why Tool Connectivity Matters for Web Developers in 2026

AI agents are becoming more capable because they can interact with external tools and systems. Learn why MCP and tool connectivity are becoming important concepts for modern developers.

Web Development

Web Development Trends in 2026: 10 Changes Developers Need to Know

From AI coding agents and React Compiler to full-stack frameworks, security automation, and agent-ready applications, these are the web development trends shaping 2026.

AI Engineering

How to Build an AI-Ready Web Application in 2026

AI-ready applications need more than an API call. Learn how to design a modern web application with AI features, structured data, security, observability, evaluation, and scalable architecture.

Web Development

Next.js 16.3 Performance: How Instant Navigations and React Compiler Change Modern Web Apps

Next.js 16.3 brings instant navigations, partial prefetching, faster development, and deeper React Compiler integration. Here’s what developers should know about building faster React applications in 2026.

Engineering

React performance optimization: what actually moves the needle

Profiling data from a production React app — which optimizations cut real load time and interaction latency, and which ones were a waste of a sprint.

Web Development

Structuring MERN APIs that survive production

How I lay out Express routes, Mongoose models, and role-based access so a MERN app stays readable after a year of feature requests.

AI Integration

Shipping AI agents that actually help customers

Lessons from building an OpenAI-powered chatbot and agent workflow for an industrial machinery business — grounding, RAG, and knowing when to hand off.

DevOps

Zero-drama deployments on DigitalOcean with Nginx, PM2 and GitHub Actions

The exact production setup I use for Node apps: process management, reverse proxy, CI/CD runners, and the failure modes worth pre-empting.

Cybersecurity

Next.js Security Update August 2026: What Developers Need to Know

Next.js is preparing a major security release for August 26, 2026. Here is what developers should know about the upcoming update, application security, dependency management, and production deployments.