Skip to content

Conversation

@luxass
Copy link
Contributor

@luxass luxass commented Oct 11, 2025

This PR resolves #1053 by adding automatic type inference for route parameters. When you define a route with parameters using app.get(), app.post(), or any other HTTP method, TypeScript now knows exactly what parameters are available in event.context.params.

Previously, event.context.params was always typed as Record<string, string> | undefined, even when the route pattern clearly defined specific parameters. Now the route pattern is parsed at the type level to extract parameter names and provide full type safety.

Route parameters are now fully typed based on the route pattern you define:

// Before: params were loosely typed
app.get("/user/:id", (event) => {
  const id = event.context.params.id; // string | undefined
});

// After: params are inferred from the route
app.get("/user/:id", (event) => {
  const id = event.context.params.id; // string ✨
});

This works with multiple parameters too:

app.get("/user/:userId/post/:postId", (event) => {
  event.context.params.userId;  // string
  event.context.params.postId;  // string
});

The existing helper functions (getRouterParam and getRouterParams) also benefit from this:

app.get("/hello/:name", (event) => {
  const params = getRouterParams(event); // { name: string }
  const name = getRouterParam(event, "name"); // string
});

Type inference works across all route registration methods like app.get(), app.post(), app.put(), app.delete(), and app.on(). Routes without parameters have params typed as undefined, so you'll know when there are no parameters available.

When you use defineHandler directly (outside of a route), the route pattern isn't available yet, so params remain untyped as Record<string, string> | undefined. You can still manually type them using the routerParams field in EventHandlerRequest if needed. However, when you inline defineHandler with a route, the params are fully typed automatically:

app.get("/hello/:name", defineHandler((event) => {
  event.context.params.name; // string - fully typed!
  
  const params = getRouterParams(event); // { name: string }
  const name = getRouterParam(event, "name"); // string
}));

The implementation leverages InferRouteParams from rou3 (h3js/rou3#168) for route pattern parsing. I have tried to make the types backward compatible, so if you catch something that doesn't work as before, just tell me and i'll fix it 😅

@luxass luxass force-pushed the feat/infer-route-params branch from 0471273 to a46b3c6 Compare October 11, 2025 06:10
@pi0
Copy link
Member

pi0 commented Oct 11, 2025

This is an awesome start. Wondering if we could pair it with InferRouteParams from rou3 (h3js/rou3#168) for app.[method] somehow

@luxass
Copy link
Contributor Author

luxass commented Oct 12, 2025

This is an awesome start. Wondering if we could pair it with InferRouteParams from rou3 (h3js/rou3#168) for app.[method] somehow

Yea, i have already started working on it locally. But ran into some beahviour issues which i am trying to figure out first 👍🏻

Will include it in this PR when i am done.

@luxass
Copy link
Contributor Author

luxass commented Oct 12, 2025

@pi0 This PR should be ready for a quick review when you have a moment - happy to adjust anything if needed 😊

I have tried cleaning the overloads from f7c9ece (#1217) up in 42a9512 (#1217), let me know if i should revert that to the multiple inline overloads approach 👍🏻

@luxass luxass marked this pull request as ready for review October 13, 2025 04:10
@luxass luxass requested a review from pi0 as a code owner October 13, 2025 04:10
@pi0
Copy link
Member

pi0 commented Oct 23, 2025

Sorry, it got delayed @luxass, we will try to review soon (also added @danielroe)

@pi0 pi0 requested a review from danielroe October 23, 2025 13:43
luxass added 16 commits October 27, 2025 11:38
* Updated the `H3EventContext` interface to accept a generic type parameter `TParams` for `params`.
* This change enhances type safety and flexibility for router parameter handling.
* Updated the `context` property in `H3Event` to infer `routerParams` more effectively.
* Added tests to verify the inference of router parameters from `EventHandlerRequest`.
* Ensured default behavior for cases without specified `routerParams`.
This feels cleaner to have the optionality of the params in the context.
The previous implementation in the pull request, removed access to the optional properties.
* Added `RouteParams` type to simplify route parameter inference.
* Updated `on`, `get`, `post`, `put`, `delete`, `patch`, `head`, `options`, `connect`, and `trace` methods to utilize the new `RouteParams` type for better type safety.
* Improved type definitions for event handlers to include inferred route parameters.
This will hopefully clean the types up a bit.
* Removed redundant `const` keyword from route type parameters in `on`, `get`, `post`, `put`, `delete`, `patch`, `head`, `options`, `connect`, and `trace` methods.
* Improved type inference for route parameters.
This should make the h3 declared class not look too complex with the overloads.

I couldn't get the `all` to use the H3HandlerInterface, some type errors in H3Core appeared 😅
@luxass luxass force-pushed the feat/infer-route-params branch from 537000c to 931281a Compare October 27, 2025 10:47
@pi0
Copy link
Member

pi0 commented Oct 28, 2025

Dear @luxass you don't need to rebase PR on all commits. I can take care of rebase before merge 👍🏼

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

infer route params

2 participants