Building Typed Express APIs with TypeScript
A freeCodeCamp tutorial walks through integrating TypeScript with Express—covering typed routes, middleware, and query params for production-ready APIs.
Written by AI. Dev Kapoor

Photo: AI. Eira Pendragon
There's a specific kind of developer pain that Express veterans know well. You're moving fast—that's the whole point—and then somewhere around midnight you're chasing a bug that boils down to: you assumed req.params.id was a number, TypeScript (or the absence of it) let you assume that, and now a production endpoint is returning garbage. Express's speed is real. So is the tax you pay for it later.
The freeCodeCamp tutorial TypeScript in Express, taught by Rachel on Scrimba, is a 74-minute attempt to collect on that debt before it compounds. It's not an intro to either technology—Rachel is explicit that you should already know the basics of both Express and TypeScript before sitting down with this one. What it offers instead is a worked example of how the two fit together: the friction points, the patterns that actually hold up, and the mental model you need to type your way through a real-world API structure.
The project anchor is a read-only pet shelter API. Simple enough that the types don't overwhelm the concepts, complex enough to surface the decisions that matter. You get list endpoints, an ID lookup, query parameter filtering across string/boolean/number types, and finally custom middleware. By the time Rachel is done, the codebase has been split into routes, controllers, and a middleware folder—all of it typed throughout.
The Friction Is the Point
One of the more honest moments in the tutorial comes early, when Rachel installs CORS and the TypeScript compiler immediately throws a fit:
"Many JavaScript packages don't ship with types by default. So we pull in community-maintained ones... It might feel like an extra step at first, but it's part of what makes TypeScript so powerful. It encourages consistency and helps catch problems early."
This is the thing TypeScript tutorials often soft-pedal: adding TypeScript to an existing JavaScript ecosystem means you're constantly reaching for @types/ packages that are maintained by the DefinitelyTyped community, not the original library authors. @types/express, @types/cors—these are separate packages with separate maintenance cycles. In most cases they're well-maintained and reliable. But they're worth knowing about, because when a library updates and the types lag, you'll feel it.
Rachel's framing—"the internet is your friend" and "TypeScript usually points you in the right direction in its error messages"—is practical and accurate. The error messages in this stack really do tell you what to do. But the underlying dynamic (community-typed dependencies) is worth naming plainly, which the tutorial gestures at without fully unpacking.
Generic Types: Where the Real Work Happens
The tutorial spends considerable time on something that often gets skipped in introductory content: Request and Response are generic types in Express, and using them without type parameters means you're leaving a lot of safety on the table.
Rachel demonstrates this by progressively tightening the Request generic across several scrims. First you get the basic Request and Response imports, which beats any. Then you get Request<{ id: string }> for typed path params. Then the full four-parameter form—Request<Params, ResBody, ReqBody, Query>—when you need to type query strings.
The Query parameter moment is illustrative. You write what looks like perfectly valid Express code to filter pets by species, call .toLowerCase() on the species value, and TypeScript stops you: Property 'toLowerCase' does not exist on type. Because to TypeScript, req.query.species could be a string, an array of strings, or a ParsedQs object—and you haven't told it which one yet. The fix is specifying the query shape in the Request generic. It's an extra step. It's also the step that prevents you from shipping an API that crashes when someone passes ?species[]=cat.
The boolean query param section is especially worth attention. The tutorial makes a clean distinction: query strings always arrive as strings, but adopted in your data is a boolean. So when you type PetQueryParams, you can be clever—rather than just string, you narrow it to 'true' | 'false' using literal types and a union. Then you parse it with JSON.parse() before comparison. This is the kind of TypeScript thinking that separates people who've actually shipped typed APIs from people who've done the tutorials.
Separation of Concerns, With Types Intact
The second half of the tutorial is a refactoring exercise as much as a typing exercise. Rachel moves from a monolithic index.ts doing everything to a structure with routes/, controllers/, and middleware/ directories. The TypeScript angle here is less about new concepts and more about discipline: every time you move code to a new file, you have to bring its types with it. Imports break. You fix them. Types that were co-located now need explicit exports and imports.
"We had to make sure all of our types like pet, pet query params, request, and response came along with us as we split things into a router and controllers. The big win here is that our app is now clean, modular, and still fully typed, ready to grow as we keep building."
This is real. One of the subtler arguments for TypeScript in larger codebases is that refactoring becomes a guided process—the compiler tells you what you broke—rather than a hunt through grep and hope. The tutorial gives you a small taste of that dynamic.
The middleware section adds NextFunction to the type vocabulary. Custom middleware in Express takes three parameters, and the third—next—has its own type. Rachel writes two pieces of middleware: validateNumericId (a guard that rejects non-numeric IDs with a 400) and pleaseAuth (a deliberately silly password gate that returns 401 unless you pass ?password=please). Both get fully typed request and response generics. The chaining of middleware—pleaseAuth runs before validateNumericId before getPetById—demonstrates how the typed pipeline composes.
What the Tutorial Doesn't Cover (and Why That's Fine)
This is a hands-on module, not a comprehensive reference. Some things that would appear in a production TypeScript/Express setup don't show up here: async route handlers and error propagation, environment-based configuration typing, database integration with typed ORMs, or the ongoing debate about whether to reach for something like zod for runtime validation instead of relying purely on TypeScript's compile-time checks.
That last one is worth a sentence. TypeScript's type system is erased at runtime. A typed Request generic tells TypeScript what shape you expect—it doesn't enforce that shape at the boundary where external data enters your application. For a read-only API built on static data (like this pet shelter example), that's fine. For an API accepting POST bodies from the public internet, you'll want runtime validation alongside compile-time typing. The tutorial's focus on GET routes sidesteps this for pedagogical clarity, but it's the next thing to learn once you've internalized what's here.
Rachel closes with a prompt toward next steps: connecting to a real database, async controllers, building a frontend that consumes the typed API. That last one is interesting—TypeScript's real leverage in a full-stack context comes from sharing types between client and server, so the shape you define on the backend can be imported on the frontend. The pet shelter API, fully typed as it is, is already set up for that.
The tutorial is a solid foundation. Whether you're convincing yourself that TypeScript is worth the overhead in an Express project, or you've already decided and need a structured walk through the patterns, it covers the ground honestly—including the friction.
By Dev Kapoor, Open Source & Developer Communities Correspondent, Buzzrag
We Watch Tech YouTube So You Don't Have To
Get the week's best tech insights, summarized and delivered to your inbox. No fluff, no spam.
More Like This
Command Line Basics: A Free Course for Beginners
freeCodeCamp and Scrimba released a free 45-minute command line course for beginners. Here's what it teaches, how it teaches it, and who it's actually for.
This 12-Hour Web Dev Course Builds 19 Real Projects
FreeCodeCamp drops a massive 12-hour tutorial teaching HTML, CSS, and JavaScript through 19 hands-on projects. Here's what makes it different.
Benchmarking Embedding Models: Open Source vs Proprietary
Explore embedding models and their role in data processing, focusing on open-source vs proprietary options.
Pretext Is Solving Web Text Layout From Scratch
Pretext, a TypeScript library by Cheng Lou, bypasses the DOM entirely to measure and lay out text fast—and it's already approaching 50,000 GitHub stars.
Building AI Agents From Scratch: An Honest Assessment
A new freeCodeCamp course from KodeKloud walks beginners through LLMs, tool-calling, and real agent architecture using the open-source OpenClaw project.
TypeScript Is Getting Rewritten in Go. Here's Why That Matters
Microsoft is porting TypeScript to Go for TypeScript 7, promising 10x speed improvements. Here's what developers need to know about versions 6 and 7.
AI Website Builder Creates Full Site From Business Card
Gary Explains tests Readdy AI's ability to generate professional websites from business cards alone. Five minutes, zero code—but what does this mean for web dev?
GPT 5.5 Isn't Actually Running Unless You Check These Settings
Most people don't realize their new AI model isn't even activated. Here's what TheAIGRID found about GPT 5.5's hidden configuration issues.
RAG·vector embedding
2026-07-25This article is indexed as a 1536-dimensional vector for semantic retrieval. Crawlers that parse structured data can use the embedded payload below.