Skip to content

Commit

Permalink
fix(valibot-validator): Fix response query types on RPC (#914)
Browse files Browse the repository at this point in the history
Fixes #899

* fix(valibot-validator): Fix query types on RPC

* Add changeset

* Remove valibot issue flatenning

* Add types test
  • Loading branch information
ajotaos authored Jan 8, 2025
1 parent d48ec05 commit c5abbc9
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 18 deletions.
5 changes: 5 additions & 0 deletions .changeset/warm-plants-thank.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@hono/valibot-validator': patch
---

Fix request query types for valibot schemas
45 changes: 27 additions & 18 deletions packages/valibot-validator/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { Context, Env, Input as HonoInput, MiddlewareHandler, ValidationTargets } from 'hono'
import type { Context, Env, Input, MiddlewareHandler, TypedResponse, ValidationTargets } from 'hono'
import { validator } from 'hono/validator'
import type {
GenericSchema,
Expand All @@ -9,10 +9,18 @@ import type {
} from 'valibot'
import { safeParseAsync } from 'valibot'

export type Hook<T extends GenericSchema | GenericSchemaAsync, E extends Env, P extends string> = (
result: SafeParseResult<T>,
export type Hook<
T extends GenericSchema | GenericSchemaAsync,
E extends Env,
P extends string,
Target extends keyof ValidationTargets = keyof ValidationTargets,
O = {}
> = (
result: SafeParseResult<T> & {
target: Target
},
c: Context<E, P>
) => Response | Promise<Response> | void | Promise<Response | void>
) => Response | void | TypedResponse<O> | Promise<Response | void | TypedResponse<O>>

type HasUndefined<T> = undefined extends T ? true : false

Expand All @@ -23,20 +31,16 @@ export const vValidator = <
P extends string,
In = InferInput<T>,
Out = InferOutput<T>,
I extends HonoInput = {
I extends Input = {
in: HasUndefined<In> extends true
? {
[K in Target]?: K extends 'json'
[K in Target]?: In extends ValidationTargets[K]
? In
: HasUndefined<keyof ValidationTargets[K]> extends true
? { [K2 in keyof In]?: ValidationTargets[K][K2] }
: { [K2 in keyof In]: ValidationTargets[K][K2] }
: { [K2 in keyof In]?: ValidationTargets[K][K2] }
}
: {
[K in Target]: K extends 'json'
[K in Target]: In extends ValidationTargets[K]
? In
: HasUndefined<keyof ValidationTargets[K]> extends true
? { [K2 in keyof In]?: ValidationTargets[K][K2] }
: { [K2 in keyof In]: ValidationTargets[K][K2] }
}
out: { [K in Target]: Out }
Expand All @@ -45,23 +49,28 @@ export const vValidator = <
>(
target: Target,
schema: T,
hook?: Hook<T, E, P>
hook?: Hook<T, E, P, Target>
): MiddlewareHandler<E, P, V> =>
// @ts-expect-error not typed well
validator(target, async (value, c) => {
const result = await safeParseAsync(schema, value)

if (hook) {
const hookResult = hook(result, c)
if (hookResult instanceof Response || hookResult instanceof Promise) {
return hookResult
const hookResult = await hook({ ...result, target }, c)
if (hookResult) {
if (hookResult instanceof Response) {
return hookResult
}

if ('response' in hookResult) {
return hookResult.response
}
}
}

if (!result.success) {
return c.json(result, 400)
}

const data = result.output as InferOutput<T>
return data
return result.output
})
25 changes: 25 additions & 0 deletions packages/valibot-validator/test/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -324,3 +324,28 @@ describe('With Hook Async', () => {
expect(res.status).toBe(400)
})
})

describe('Test types', () => {
it('Should return correct types when validating a query', () => {
const app = new Hono()

const routes = app.post(
'/',
vValidator(
'query',
object({
foo: string(),
})
),
(c) => {
return c.json(c.req.valid('query'))
}
)

type T = ExtractSchema<typeof routes>

type Actual = T['/']['$post']['input']['query']
type Expected = { foo: string }
type verify = Expect<Equal<Expected, Actual>>
})
})

0 comments on commit c5abbc9

Please sign in to comment.