@di-framework/di-framework-http 0.0.0-prerelease.307 → 0.0.0-prerelease.308

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -8,6 +8,12 @@ export type Multipart<T> = {
8
8
  readonly __kind: "multipart";
9
9
  readonly __type?: T;
10
10
  };
11
+ export type PathParams<T> = {
12
+ readonly __pathParams?: T;
13
+ };
14
+ export type QueryParams<T> = {
15
+ readonly __queryParams?: T;
16
+ };
11
17
  /** Spec types you’ll use in generics */
12
18
  export type RequestSpec<BodySpec = unknown> = {
13
19
  readonly __req?: BodySpec;
@@ -17,9 +23,13 @@ export type ResponseSpec<Body = unknown> = {
17
23
  };
18
24
  /** Map a BodySpec to the actual req.content type */
19
25
  type ContentOf<BodySpec> = BodySpec extends Json<infer T> ? T : BodySpec extends Multipart<infer _T> ? FormData : unknown;
26
+ type PathParamsOf<BodySpec> = BodySpec extends PathParams<infer T> ? T : Record<string, string>;
27
+ type QueryParamsOf<BodySpec> = BodySpec extends QueryParams<infer T> ? T : Record<string, string | string[] | undefined>;
20
28
  /** The actual request type your handlers receive */
21
- export type TypedRequest<ReqSpec> = IRequest & {
29
+ export type TypedRequest<ReqSpec> = Omit<IRequest, "params" | "query"> & {
22
30
  content: ContentOf<ReqSpec extends RequestSpec<infer B> ? B : never>;
31
+ params: PathParamsOf<ReqSpec extends RequestSpec<infer B> ? B : never>;
32
+ query: QueryParamsOf<ReqSpec extends RequestSpec<infer B> ? B : never>;
23
33
  };
24
34
  /** Typed response helper (phantom only) */
25
35
  export type TypedResponse<ResSpec> = globalThis.Response & {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@di-framework/di-framework-http",
3
- "version": "0.0.0-prerelease.307",
3
+ "version": "0.0.0-prerelease.308",
4
4
  "description": "Extends di-framework with HTTP features",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.js",
@@ -40,7 +40,7 @@
40
40
  "typescript": "^5"
41
41
  },
42
42
  "peerDependencies": {
43
- "@di-framework/di-framework": "^0.0.0-prerelease.306",
43
+ "@di-framework/di-framework": "^0.0.0-prerelease.308",
44
44
  "typescript": "^5"
45
45
  }
46
46
  }
@@ -5,6 +5,8 @@ import {
5
5
  type Multipart,
6
6
  type RequestSpec,
7
7
  type ResponseSpec,
8
+ type PathParams,
9
+ type QueryParams,
8
10
  } from "./typed-router.ts";
9
11
 
10
12
  describe("TypedRouter", () => {
@@ -192,4 +194,23 @@ describe("TypedRouter", () => {
192
194
  const res = await router.fetch(req);
193
195
  expect(res.status).toBe(415);
194
196
  });
197
+
198
+ it("should type params and query from RequestSpec", async () => {
199
+ const router = TypedRouter();
200
+ router.get<
201
+ RequestSpec<PathParams<{ id: string }> & QueryParams<{ search?: string }>>,
202
+ ResponseSpec<{ id: string; search?: string }>
203
+ >("/item/:id", (req) => {
204
+ // Type testing:
205
+ const id: string = req.params.id;
206
+ const search: string | undefined = req.query.search;
207
+ return json({ id, search });
208
+ });
209
+
210
+ const req = new Request("http://localhost/item/123?search=test");
211
+ const res = await router.fetch(req);
212
+ expect(res.status).toBe(200);
213
+ const body = (await res.json()) as any;
214
+ expect(body).toEqual({ id: "123", search: "test" });
215
+ });
195
216
  });
@@ -11,6 +11,8 @@ export type Multipart<T> = {
11
11
  readonly __kind: "multipart";
12
12
  readonly __type?: T;
13
13
  };
14
+ export type PathParams<T> = { readonly __pathParams?: T };
15
+ export type QueryParams<T> = { readonly __queryParams?: T };
14
16
 
15
17
  /** Spec types you’ll use in generics */
16
18
  export type RequestSpec<BodySpec = unknown> = { readonly __req?: BodySpec };
@@ -24,9 +26,19 @@ type ContentOf<BodySpec> =
24
26
  ? FormData
25
27
  : unknown;
26
28
 
29
+ type PathParamsOf<BodySpec> = BodySpec extends PathParams<infer T>
30
+ ? T
31
+ : Record<string, string>;
32
+
33
+ type QueryParamsOf<BodySpec> = BodySpec extends QueryParams<infer T>
34
+ ? T
35
+ : Record<string, string | string[] | undefined>;
36
+
27
37
  /** The actual request type your handlers receive */
28
- export type TypedRequest<ReqSpec> = IRequest & {
38
+ export type TypedRequest<ReqSpec> = Omit<IRequest, "params" | "query"> & {
29
39
  content: ContentOf<ReqSpec extends RequestSpec<infer B> ? B : never>;
40
+ params: PathParamsOf<ReqSpec extends RequestSpec<infer B> ? B : never>;
41
+ query: QueryParamsOf<ReqSpec extends RequestSpec<infer B> ? B : never>;
30
42
  };
31
43
 
32
44
  /** Typed response helper (phantom only) */