Skip to content

Commit 0ca5bbf

Browse files
committed
automatically infer types from validation object
1 parent 9258009 commit 0ca5bbf

3 files changed

Lines changed: 166 additions & 130 deletions

File tree

packages/event-handler/src/http/Router.ts

Lines changed: 110 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ import type {
2828
HttpResolveOptions,
2929
HttpRouteOptions,
3030
HttpRouterOptions,
31+
InferReqSchema,
32+
InferResBody,
3133
Middleware,
3234
MiddlewareOrHandler,
3335
Path,
@@ -646,22 +648,25 @@ class Router {
646648
public get(path: Path, middleware: Middleware[], handler: RouteHandler): void;
647649
public get(path: Path): MethodDecorator;
648650
public get(path: Path, middleware: Middleware[]): MethodDecorator;
649-
public get<
650-
TReq extends ReqSchema = ReqSchema,
651-
TResBody extends HandlerResponse = HandlerResponse,
652-
>(
651+
public get<TResBody extends HandlerResponse>(
653652
path: Path,
654-
handler: TypedRouteHandler<TReq, TResBody>,
655-
options: { validation: ValidationConfig<TReq, TResBody> }
653+
handler: RouteHandler<TResBody>
656654
): void;
657-
public get<
658-
TReq extends ReqSchema = ReqSchema,
659-
TResBody extends HandlerResponse = HandlerResponse,
660-
>(
655+
public get<TResBody extends HandlerResponse>(
656+
path: Path,
657+
middleware: Middleware[],
658+
handler: RouteHandler<TResBody>
659+
): void;
660+
public get<V extends ValidationConfig>(
661+
path: Path,
662+
handler: TypedRouteHandler<InferReqSchema<V>, InferResBody<V>>,
663+
options: { validation: V }
664+
): void;
665+
public get<V extends ValidationConfig>(
661666
path: Path,
662667
middleware: Middleware[],
663-
handler: TypedRouteHandler<TReq, TResBody>,
664-
options: { validation: ValidationConfig<TReq, TResBody> }
668+
handler: TypedRouteHandler<InferReqSchema<V>, InferResBody<V>>,
669+
options: { validation: V }
665670
): void;
666671
public get<
667672
TReq extends ReqSchema = ReqSchema,
@@ -672,7 +677,7 @@ class Router {
672677
handlerOrOptions?: HandlerOrOptions<TReq, TResBody>,
673678
options?: { validation: ValidationConfig<TReq, TResBody> }
674679
): MethodDecorator | undefined {
675-
return this.#handleHttpMethod<TReq, TResBody>(
680+
return this.#handleHttpMethod(
676681
HttpVerbs.GET,
677682
path,
678683
middlewareOrHandler,
@@ -689,22 +694,25 @@ class Router {
689694
): void;
690695
public post(path: Path): MethodDecorator;
691696
public post(path: Path, middleware: Middleware[]): MethodDecorator;
692-
public post<
693-
TReq extends ReqSchema = ReqSchema,
694-
TResBody extends HandlerResponse = HandlerResponse,
695-
>(
697+
public post<TResBody extends HandlerResponse>(
696698
path: Path,
697-
handler: TypedRouteHandler<TReq, TResBody>,
698-
options: { validation: ValidationConfig<TReq, TResBody> }
699+
handler: RouteHandler<TResBody>
699700
): void;
700-
public post<
701-
TReq extends ReqSchema = ReqSchema,
702-
TResBody extends HandlerResponse = HandlerResponse,
703-
>(
701+
public post<TResBody extends HandlerResponse>(
704702
path: Path,
705703
middleware: Middleware[],
706-
handler: TypedRouteHandler<TReq, TResBody>,
707-
options: { validation: ValidationConfig<TReq, TResBody> }
704+
handler: RouteHandler<TResBody>
705+
): void;
706+
public post<V extends ValidationConfig>(
707+
path: Path,
708+
handler: TypedRouteHandler<InferReqSchema<V>, InferResBody<V>>,
709+
options: { validation: V }
710+
): void;
711+
public post<V extends ValidationConfig>(
712+
path: Path,
713+
middleware: Middleware[],
714+
handler: TypedRouteHandler<InferReqSchema<V>, InferResBody<V>>,
715+
options: { validation: V }
708716
): void;
709717
public post<
710718
TReq extends ReqSchema = ReqSchema,
@@ -715,7 +723,7 @@ class Router {
715723
handlerOrOptions?: HandlerOrOptions<TReq, TResBody>,
716724
options?: { validation: ValidationConfig<TReq, TResBody> }
717725
): MethodDecorator | undefined {
718-
return this.#handleHttpMethod<TReq, TResBody>(
726+
return this.#handleHttpMethod(
719727
HttpVerbs.POST,
720728
path,
721729
middlewareOrHandler,
@@ -728,22 +736,25 @@ class Router {
728736
public put(path: Path, middleware: Middleware[], handler: RouteHandler): void;
729737
public put(path: Path): MethodDecorator;
730738
public put(path: Path, middleware: Middleware[]): MethodDecorator;
731-
public put<
732-
TReq extends ReqSchema = ReqSchema,
733-
TResBody extends HandlerResponse = HandlerResponse,
734-
>(
739+
public put<TResBody extends HandlerResponse>(
735740
path: Path,
736-
handler: TypedRouteHandler<TReq, TResBody>,
737-
options: { validation: ValidationConfig<TReq, TResBody> }
741+
handler: RouteHandler<TResBody>
738742
): void;
739-
public put<
740-
TReq extends ReqSchema = ReqSchema,
741-
TResBody extends HandlerResponse = HandlerResponse,
742-
>(
743+
public put<TResBody extends HandlerResponse>(
743744
path: Path,
744745
middleware: Middleware[],
745-
handler: TypedRouteHandler<TReq, TResBody>,
746-
options: { validation: ValidationConfig<TReq, TResBody> }
746+
handler: RouteHandler<TResBody>
747+
): void;
748+
public put<V extends ValidationConfig>(
749+
path: Path,
750+
handler: TypedRouteHandler<InferReqSchema<V>, InferResBody<V>>,
751+
options: { validation: V }
752+
): void;
753+
public put<V extends ValidationConfig>(
754+
path: Path,
755+
middleware: Middleware[],
756+
handler: TypedRouteHandler<InferReqSchema<V>, InferResBody<V>>,
757+
options: { validation: V }
747758
): void;
748759
public put<
749760
TReq extends ReqSchema = ReqSchema,
@@ -754,7 +765,7 @@ class Router {
754765
handlerOrOptions?: HandlerOrOptions<TReq, TResBody>,
755766
options?: { validation: ValidationConfig<TReq, TResBody> }
756767
): MethodDecorator | undefined {
757-
return this.#handleHttpMethod<TReq, TResBody>(
768+
return this.#handleHttpMethod(
758769
HttpVerbs.PUT,
759770
path,
760771
middlewareOrHandler,
@@ -771,22 +782,25 @@ class Router {
771782
): void;
772783
public patch(path: Path): MethodDecorator;
773784
public patch(path: Path, middleware: Middleware[]): MethodDecorator;
774-
public patch<
775-
TReq extends ReqSchema = ReqSchema,
776-
TResBody extends HandlerResponse = HandlerResponse,
777-
>(
785+
public patch<TResBody extends HandlerResponse>(
778786
path: Path,
779-
handler: TypedRouteHandler<TReq, TResBody>,
780-
options: { validation: ValidationConfig<TReq, TResBody> }
787+
handler: RouteHandler<TResBody>
781788
): void;
782-
public patch<
783-
TReq extends ReqSchema = ReqSchema,
784-
TResBody extends HandlerResponse = HandlerResponse,
785-
>(
789+
public patch<TResBody extends HandlerResponse>(
790+
path: Path,
791+
middleware: Middleware[],
792+
handler: RouteHandler<TResBody>
793+
): void;
794+
public patch<V extends ValidationConfig>(
795+
path: Path,
796+
handler: TypedRouteHandler<InferReqSchema<V>, InferResBody<V>>,
797+
options: { validation: V }
798+
): void;
799+
public patch<V extends ValidationConfig>(
786800
path: Path,
787801
middleware: Middleware[],
788-
handler: TypedRouteHandler<TReq, TResBody>,
789-
options: { validation: ValidationConfig<TReq, TResBody> }
802+
handler: TypedRouteHandler<InferReqSchema<V>, InferResBody<V>>,
803+
options: { validation: V }
790804
): void;
791805
public patch<
792806
TReq extends ReqSchema = ReqSchema,
@@ -814,22 +828,25 @@ class Router {
814828
): void;
815829
public delete(path: Path): MethodDecorator;
816830
public delete(path: Path, middleware: Middleware[]): MethodDecorator;
817-
public delete<
818-
TReq extends ReqSchema = ReqSchema,
819-
TResBody extends HandlerResponse = HandlerResponse,
820-
>(
831+
public delete<TResBody extends HandlerResponse>(
821832
path: Path,
822-
handler: TypedRouteHandler<TReq, TResBody>,
823-
options: { validation: ValidationConfig<TReq, TResBody> }
833+
handler: RouteHandler<TResBody>
824834
): void;
825-
public delete<
826-
TReq extends ReqSchema = ReqSchema,
827-
TResBody extends HandlerResponse = HandlerResponse,
828-
>(
835+
public delete<TResBody extends HandlerResponse>(
836+
path: Path,
837+
middleware: Middleware[],
838+
handler: RouteHandler<TResBody>
839+
): void;
840+
public delete<V extends ValidationConfig>(
841+
path: Path,
842+
handler: TypedRouteHandler<InferReqSchema<V>, InferResBody<V>>,
843+
options: { validation: V }
844+
): void;
845+
public delete<V extends ValidationConfig>(
829846
path: Path,
830847
middleware: Middleware[],
831-
handler: TypedRouteHandler<TReq, TResBody>,
832-
options: { validation: ValidationConfig<TReq, TResBody> }
848+
handler: TypedRouteHandler<InferReqSchema<V>, InferResBody<V>>,
849+
options: { validation: V }
833850
): void;
834851
public delete<
835852
TReq extends ReqSchema = ReqSchema,
@@ -857,22 +874,25 @@ class Router {
857874
): void;
858875
public head(path: Path): MethodDecorator;
859876
public head(path: Path, middleware: Middleware[]): MethodDecorator;
860-
public head<
861-
TReq extends ReqSchema = ReqSchema,
862-
TResBody extends HandlerResponse = HandlerResponse,
863-
>(
877+
public head<TResBody extends HandlerResponse>(
864878
path: Path,
865-
handler: TypedRouteHandler<TReq, TResBody>,
866-
options: { validation: ValidationConfig<TReq, TResBody> }
879+
handler: RouteHandler<TResBody>
867880
): void;
868-
public head<
869-
TReq extends ReqSchema = ReqSchema,
870-
TResBody extends HandlerResponse = HandlerResponse,
871-
>(
881+
public head<TResBody extends HandlerResponse>(
882+
path: Path,
883+
middleware: Middleware[],
884+
handler: RouteHandler<TResBody>
885+
): void;
886+
public head<V extends ValidationConfig>(
887+
path: Path,
888+
handler: TypedRouteHandler<InferReqSchema<V>, InferResBody<V>>,
889+
options: { validation: V }
890+
): void;
891+
public head<V extends ValidationConfig>(
872892
path: Path,
873893
middleware: Middleware[],
874-
handler: TypedRouteHandler<TReq, TResBody>,
875-
options: { validation: ValidationConfig<TReq, TResBody> }
894+
handler: TypedRouteHandler<InferReqSchema<V>, InferResBody<V>>,
895+
options: { validation: V }
876896
): void;
877897
public head<
878898
TReq extends ReqSchema = ReqSchema,
@@ -900,22 +920,25 @@ class Router {
900920
): void;
901921
public options(path: Path): MethodDecorator;
902922
public options(path: Path, middleware: Middleware[]): MethodDecorator;
903-
public options<
904-
TReq extends ReqSchema = ReqSchema,
905-
TResBody extends HandlerResponse = HandlerResponse,
906-
>(
923+
public options<TResBody extends HandlerResponse>(
907924
path: Path,
908-
handler: TypedRouteHandler<TReq, TResBody>,
909-
options: { validation: ValidationConfig<TReq, TResBody> }
925+
handler: RouteHandler<TResBody>
910926
): void;
911-
public options<
912-
TReq extends ReqSchema = ReqSchema,
913-
TResBody extends HandlerResponse = HandlerResponse,
914-
>(
927+
public options<TResBody extends HandlerResponse>(
928+
path: Path,
929+
middleware: Middleware[],
930+
handler: RouteHandler<TResBody>
931+
): void;
932+
public options<V extends ValidationConfig>(
933+
path: Path,
934+
handler: TypedRouteHandler<InferReqSchema<V>, InferResBody<V>>,
935+
options: { validation: V }
936+
): void;
937+
public options<V extends ValidationConfig>(
915938
path: Path,
916939
middleware: Middleware[],
917-
handler: TypedRouteHandler<TReq, TResBody>,
918-
options: { validation: ValidationConfig<TReq, TResBody> }
940+
handler: TypedRouteHandler<InferReqSchema<V>, InferResBody<V>>,
941+
options: { validation: V }
919942
): void;
920943
public options<
921944
TReq extends ReqSchema = ReqSchema,

packages/event-handler/src/types/http.ts

Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -354,15 +354,12 @@ type RequestValidationConfig<TReq extends ReqSchema = ReqSchema> =
354354
*/
355355
type ResponseValidationConfig<T extends HandlerResponse = HandlerResponse> =
356356
| {
357-
body: StandardSchemaV1<HandlerResponse, T>;
358-
headers?: StandardSchemaV1<
359-
Record<string, string>,
360-
Record<string, string>
361-
>;
357+
body: StandardSchemaV1<unknown, T>;
358+
headers?: StandardSchemaV1<unknown, Record<string, string>>;
362359
}
363360
| {
364-
body?: StandardSchemaV1<HandlerResponse, T>;
365-
headers: StandardSchemaV1<Record<string, string>, Record<string, string>>;
361+
body?: StandardSchemaV1<unknown, T>;
362+
headers: StandardSchemaV1<unknown, Record<string, string>>;
366363
};
367364

368365
/**
@@ -382,6 +379,39 @@ type ValidationConfig<
382379
res: ResponseValidationConfig<TResBody>;
383380
};
384381

382+
/**
383+
* Infers the `ReqSchema` type from a `ValidationConfig` by extracting the output types
384+
* from each request schema (body, headers, path, query).
385+
*/
386+
type InferReqSchema<V extends ValidationConfig> = V extends {
387+
req: infer R;
388+
}
389+
? {
390+
body: R extends { body: StandardSchemaV1<infer _I, infer O> }
391+
? O
392+
: undefined;
393+
headers: R extends { headers: StandardSchemaV1<infer _I, infer O> }
394+
? O
395+
: undefined;
396+
path: R extends { path: StandardSchemaV1<infer _I, infer O> }
397+
? O
398+
: undefined;
399+
query: R extends { query: StandardSchemaV1<infer _I, infer O> }
400+
? O
401+
: undefined;
402+
}
403+
: ReqSchema;
404+
405+
/**
406+
* Infers the response body type from a `ValidationConfig` by extracting the output type
407+
* from the response body schema.
408+
*/
409+
type InferResBody<V extends ValidationConfig> = V extends {
410+
res: { body: StandardSchemaV1<infer _I, infer O> };
411+
}
412+
? O
413+
: HandlerResponse;
414+
385415
/**
386416
* Validation error details
387417
*/
@@ -454,4 +484,6 @@ export type {
454484
MiddlewareOrHandler,
455485
HandlerOrOptions,
456486
ReqSchema,
487+
InferReqSchema,
488+
InferResBody,
457489
};

0 commit comments

Comments
 (0)