From 448a0027ba2b07f392cccac19edffb80513c4f23 Mon Sep 17 00:00:00 2001 From: Yusuke Wada Date: Thu, 6 Jun 2024 16:48:34 +0900 Subject: [PATCH] feat(context): `c.redirect()` supports `TypedResponse` (#2908) --- src/client/client.test.ts | 56 ++++++++++++++++++++++++++++++++++++++- src/context.ts | 7 +++-- src/types.ts | 2 +- 3 files changed, 61 insertions(+), 4 deletions(-) diff --git a/src/client/client.test.ts b/src/client/client.test.ts index bac60bcc5..94daaf42a 100644 --- a/src/client/client.test.ts +++ b/src/client/client.test.ts @@ -10,7 +10,7 @@ import { parse } from '../utils/cookie' import type { Equal, Expect } from '../utils/types' import { validator } from '../validator' import { hc } from './client' -import type { InferRequestType, InferResponseType } from './types' +import type { ClientResponse, InferRequestType, InferResponseType } from './types' describe('Basic - JSON', () => { const app = new Hono() @@ -1081,3 +1081,57 @@ describe('Text response', () => { type verify = Expect> }) }) + +describe('Redirect response - only types', () => { + const server = setupServer( + http.get('http://localhost/', async () => { + return HttpResponse.redirect('/') + }) + ) + + beforeAll(() => server.listen()) + afterEach(() => server.resetHandlers()) + afterAll(() => server.close()) + + const condition = () => true + const app = new Hono().get('/', async (c) => { + const ok = condition() + const temporary = condition() + if (ok) { + return c.json({ ok: true }, 200) + } + if (temporary) { + return c.redirect('/302') + } + return c.redirect('/301', 301) + }) + + const client = hc('http://localhost/') + const req = client.index.$get + + it('Should infer request type the type correctly', () => { + type Actual = InferResponseType + type Expected = + | { + ok: boolean + } + | undefined + type verify = Expect> + }) + + it('Should infer response type correctly', async () => { + const res = await req() + if (res.ok) { + const data = await res.json() + expectTypeOf(data).toMatchTypeOf({ ok: true }) + } + if (res.status === 301) { + type Expected = ClientResponse + type verify = Expect> + } + if (res.status === 302) { + type Expected = ClientResponse + type verify = Expect> + } + }) +}) diff --git a/src/context.ts b/src/context.ts index cacf46e32..aa3264b11 100644 --- a/src/context.ts +++ b/src/context.ts @@ -716,10 +716,13 @@ export class Context< * }) * ``` */ - redirect = (location: string, status: RedirectStatusCode = 302): Response => { + redirect = ( + location: string, + status?: T + ): Response & TypedResponse => { this.#headers ??= new Headers() this.#headers.set('Location', location) - return this.newResponse(null, status) + return this.newResponse(null, status ?? 302) as any } /** diff --git a/src/types.ts b/src/types.ts index 2b0294230..0e631e8d3 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1741,7 +1741,7 @@ export type MergePath = B extends '' ////// ////// //////////////////////////////////////// -export type KnownResponseFormat = 'json' | 'text' +export type KnownResponseFormat = 'json' | 'text' | 'redirect' export type ResponseFormat = KnownResponseFormat | string export type TypedResponse<