Description
The Valibot plugin currently emits some schemas as a bare v.GenericSchema when the generated schema contains v.lazy(...) references.
Because v.GenericSchema defaults to GenericSchema<unknown, unknown>, any other schema that uses that generated schema inside v.array(...) loses the array element type. The resulting v.InferOutput<typeof schema> contains unknown[] instead of the expected referenced type array.
I can submit a pull request if the preferred fix is to avoid emitting the GenericSchema annotation and let TypeScript infer the concrete schema type.
Bug description
Given generated code like this:
// Actual
export const vChild: v.GenericSchema = v.object({
id: v.optional(v.number()),
next: v.optional(v.lazy(() => vChild)),
});
export const vParent = v.object({
id: v.number(),
children: v.optional(v.array(vChild)),
});
TypeScript infers:
v.InferOutput<typeof vParent>
// {
// id: number;
// children?: unknown[] | undefined;
// }
Expected:
v.InferOutput<typeof vParent>
// {
// id: number;
// children?: Child[] | undefined;
// }
This happens because v.GenericSchema without type parameters is equivalent to v.GenericSchema<unknown, unknown>.
A minimal Valibot-only reproduction (you can check in browser in valibot's playground):
import * as v from 'valibot';
type Child = {
id?: number;
};
type Parent = {
id: number;
children?: Child[];
};
const childSchema: v.GenericSchema = v.object({
id: v.optional(v.number()),
});
const parentSchema = v.object({
id: v.number(),
children: v.optional(v.array(childSchema)),
});
const parent: Parent = {
id: 1,
children: [],
};
const parsedParent = v.parse(parentSchema, parent);
export const result: Parent = parsedParent;
TypeScript error:
Type '{ id: number; children?: unknown[] | undefined; }' is not assignable to type 'Parent'.
Types of property 'children' are incompatible.
Type 'unknown[] | undefined' is not assignable to type 'Child[] | undefined'.
Type 'unknown[]' is not assignable to type 'Child[]'.
Type 'unknown' is not assignable to type 'Child'.
The generated schema should let TypeScript infer the concrete schema type:
// Expected
export const vChild = v.object({
id: v.optional(v.number()),
next: v.optional(v.lazy(() => vChild)),
});
This keeps the output type intact, so v.array(vChild) is inferred as Child[] instead of unknown[].
Reproducible example or configuration
Minimal package setup:
{
"type": "module",
"scripts": {
"typecheck": "tsc --noEmit"
},
"dependencies": {
"@hey-api/openapi-ts": "0.98.1",
"valibot": "1.3.1"
},
"devDependencies": {
"typescript": "5.8.3"
}
}
Minimal Hey API config:
import { defineConfig } from '@hey-api/openapi-ts';
export default defineConfig({
input: './openapi.yaml',
output: './generated',
plugins: [
{
enums: 'javascript',
name: '@hey-api/typescript',
},
{
name: 'valibot',
},
],
});
Command:
npx openapi-ts
npx tsc --noEmit
There is also a reduced Valibot-only reproduction in:
examples/valibot-generic-schema-repro
Run it with:
npm install
npm run typecheck
OpenAPI specification (optional)
openapi: 3.1.0
info:
title: Valibot GenericSchema Repro
version: 1.0.0
paths:
/parents:
get:
operationId: getParents
responses:
'200':
description: OK
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/Parent'
components:
schemas:
Parent:
type: object
required:
- id
properties:
id:
type: number
children:
type: array
items:
$ref: '#/components/schemas/Child'
Child:
type: object
properties:
id:
type: number
next:
$ref: '#/components/schemas/Child'
The recursive Child.next reference makes the Valibot plugin generate a schema that needs v.lazy(...). The issue is not the lazy runtime shape itself, but the emitted bare v.GenericSchema type annotation. Removing that annotation lets TypeScript infer the concrete Valibot schema type.
System information (optional)
@hey-api/openapi-ts: 0.98.1
valibot: 1.3.1
typescript: 5.8.3
node: 24.16.0
npm: 11.13.0
Description
The Valibot plugin currently emits some schemas as a bare
v.GenericSchemawhen the generated schema containsv.lazy(...)references.Because
v.GenericSchemadefaults toGenericSchema<unknown, unknown>, any other schema that uses that generated schema insidev.array(...)loses the array element type. The resultingv.InferOutput<typeof schema>containsunknown[]instead of the expected referenced type array.I can submit a pull request if the preferred fix is to avoid emitting the
GenericSchemaannotation and let TypeScript infer the concrete schema type.Bug description
Given generated code like this:
TypeScript infers:
Expected:
This happens because
v.GenericSchemawithout type parameters is equivalent tov.GenericSchema<unknown, unknown>.A minimal Valibot-only reproduction (you can check in browser in valibot's playground):
TypeScript error:
The generated schema should let TypeScript infer the concrete schema type:
This keeps the output type intact, so
v.array(vChild)is inferred asChild[]instead ofunknown[].Reproducible example or configuration
Minimal package setup:
{ "type": "module", "scripts": { "typecheck": "tsc --noEmit" }, "dependencies": { "@hey-api/openapi-ts": "0.98.1", "valibot": "1.3.1" }, "devDependencies": { "typescript": "5.8.3" } }Minimal Hey API config:
Command:
There is also a reduced Valibot-only reproduction in:
Run it with:
OpenAPI specification (optional)
The recursive
Child.nextreference makes the Valibot plugin generate a schema that needsv.lazy(...). The issue is not the lazy runtime shape itself, but the emitted barev.GenericSchematype annotation. Removing that annotation lets TypeScript infer the concrete Valibot schema type.System information (optional)