-
-
Notifications
You must be signed in to change notification settings - Fork 1
Description
Issue
Discriminated unions fail when including schemas with additionalProperties
Problem Description
When generating Zod schemas from OpenAPI specs that include discriminated unions with schemas that have additionalProperties: true, the generated code fails with the error:
Error: A discriminator value for key kind could not be extracted from all schema options
This occurs because Zod's discriminatedUnion requires literal types for the discriminator property, but schemas with additionalProperties: true have a generic string type for their discriminator.
Example
Given this OpenAPI schema:
{
"components": {
"schemas": {
"KnownStrategy": {
"type": "object",
"required": ["kind"],
"properties": {
"kind": {
"type": "string",
"enum": ["KNOWN"]
},
"data": {
"type": "string"
}
}
},
"UnknownStrategy": {
"type": "object",
"required": ["kind"],
"properties": {
"kind": {
"type": "string"
}
},
"additionalProperties": true
},
"Strategy": {
"oneOf": [
{ "$ref": "#/components/schemas/KnownStrategy" },
{ "$ref": "#/components/schemas/UnknownStrategy" }
],
"discriminator": {
"propertyName": "kind"
}
}
}
}
}The current generator produces:
export const KnownStrategySchema = z.object({
kind: z.literal('KNOWN'),
data: z.string()
});
export const UnknownStrategySchema = z.object({
kind: z.string()
}).catchall(z.any());
export const StrategySchema = z.discriminatedUnion('kind', [
KnownStrategySchema,
UnknownStrategySchema // This causes the error because kind is not a literal
]);Expected Behavior
The generator should handle unknown strategies (those with additionalProperties: true) differently by:
- Detecting schemas with
additionalProperties: true - For discriminated unions that include unknown strategies:
- Create a union of:
- A discriminated union containing only known strategies
- Unknown strategies as separate union members
- Create a union of:
Example of expected output:
export const StrategySchema = z.union([
z.discriminatedUnion('kind', [
KnownStrategySchema // Only known strategies in the discriminated union
]),
UnknownStrategySchema // Unknown strategies as a separate union member
]);Use Case
This is particularly important for API designs that support plugin/extension patterns where:
- Core functionality uses known strategy types with strict validation
- Plugins/extensions can add new strategy types without modifying the core schema
- The API needs to handle both known and unknown strategies
Impact
- Current workaround is to remove unknown strategies from the schema, which breaks the plugin/extension pattern
- Forces API designers to choose between type safety and extensibility
- Makes it difficult to implement manifest-based strategy registration
Proposed Solution
Modify the schema generator to:
- Detect schemas with
additionalProperties: true - Split union members into known and unknown strategies
- Generate appropriate Zod schemas based on the presence of unknown strategies
This would allow the API to maintain type safety for known strategies while supporting extensibility through unknown strategies.
Additional Context
- This is a common pattern in plugin architectures
- The OpenAPI spec correctly supports this through
additionalProperties - The issue is specifically with how the Zod schema generator handles these cases
Metadata
Metadata
Assignees
Labels
Type
Projects
Status