Skip to content

Commit

Permalink
feat(context): c.redirect() supports TypedResponse (honojs#2908)
Browse files Browse the repository at this point in the history
  • Loading branch information
yusukebe authored Jun 6, 2024
1 parent 5beac4e commit 448a002
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 4 deletions.
56 changes: 55 additions & 1 deletion src/client/client.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down Expand Up @@ -1081,3 +1081,57 @@ describe('Text response', () => {
type verify = Expect<Equal<Expected, Actual>>
})
})

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<typeof app>('http://localhost/')
const req = client.index.$get

it('Should infer request type the type correctly', () => {
type Actual = InferResponseType<typeof req>
type Expected =
| {
ok: boolean
}
| undefined
type verify = Expect<Equal<Expected, Actual>>
})

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<undefined, 301, 'redirect'>
type verify = Expect<Equal<Expected, typeof res>>
}
if (res.status === 302) {
type Expected = ClientResponse<undefined, 302, 'redirect'>
type verify = Expect<Equal<Expected, typeof res>>
}
})
})
7 changes: 5 additions & 2 deletions src/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -716,10 +716,13 @@ export class Context<
* })
* ```
*/
redirect = (location: string, status: RedirectStatusCode = 302): Response => {
redirect = <T extends RedirectStatusCode = 302>(
location: string,
status?: T
): Response & TypedResponse<undefined, T, 'redirect'> => {
this.#headers ??= new Headers()
this.#headers.set('Location', location)
return this.newResponse(null, status)
return this.newResponse(null, status ?? 302) as any
}

/**
Expand Down
2 changes: 1 addition & 1 deletion src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1741,7 +1741,7 @@ export type MergePath<A extends string, B extends string> = B extends ''
////// //////
////////////////////////////////////////

export type KnownResponseFormat = 'json' | 'text'
export type KnownResponseFormat = 'json' | 'text' | 'redirect'
export type ResponseFormat = KnownResponseFormat | string

export type TypedResponse<
Expand Down

0 comments on commit 448a002

Please sign in to comment.