Context that's typed as it grows
A middleware says what it adds to the context. The ones after it see that as typed properties, and using something nothing has added is a compile error.
Build each route as a chain of small steps. Each step adds to the request's context, and TypeScript knows what every step after it can use.