Skip to content

Commit 6fd3b39

Browse files
fix(JSONSchema): add type for enum (#4577)
* fix(JSONSchema): add type for enum * Tweak --------- Co-authored-by: Colin McDonnell <[email protected]>
1 parent dc2c0b0 commit 6fd3b39

File tree

4 files changed

+35
-14
lines changed

4 files changed

+35
-14
lines changed

packages/zod/src/v4/classic/tests/to-json-schema.test.ts

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -639,15 +639,35 @@ describe("toJSONSchema", () => {
639639

640640
// enum
641641
test("enum", () => {
642-
const schema = z.enum(["a", "b", "c"]);
643-
expect(z.toJSONSchema(schema)).toMatchInlineSnapshot(`
642+
const a = z.enum(["a", "b", "c"]);
643+
expect(z.toJSONSchema(a)).toMatchInlineSnapshot(`
644644
{
645645
"$schema": "https://json-schema.org/draft/2020-12/schema",
646646
"enum": [
647647
"a",
648648
"b",
649649
"c",
650650
],
651+
"type": "string",
652+
}
653+
`);
654+
655+
enum B {
656+
A = 0,
657+
B = 1,
658+
C = 2,
659+
}
660+
661+
const b = z.enum(B);
662+
expect(z.toJSONSchema(b)).toMatchInlineSnapshot(`
663+
{
664+
"$schema": "https://json-schema.org/draft/2020-12/schema",
665+
"enum": [
666+
0,
667+
1,
668+
2,
669+
],
670+
"type": "number",
651671
}
652672
`);
653673
});

packages/zod/src/v4/core/schemas.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2636,10 +2636,7 @@ export interface $ZodEnum<T extends util.EnumLike = util.EnumLike> extends $ZodT
26362636
export const $ZodEnum: core.$constructor<$ZodEnum> = /*@__PURE__*/ core.$constructor("$ZodEnum", (inst, def) => {
26372637
$ZodType.init(inst, def);
26382638

2639-
const numericValues = Object.values(def.entries).filter((v) => typeof v === "number");
2640-
const values = Object.entries(def.entries)
2641-
.filter(([k, _]) => numericValues.indexOf(+k) === -1)
2642-
.map(([_, v]) => v);
2639+
const values = util.getEnumValues(def.entries);
26432640

26442641
inst._zod.values = new Set<util.Primitive>(values);
26452642

packages/zod/src/v4/core/to-json-schema.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import type * as checks from "./checks.js";
22
import type * as JSONSchema from "./json-schema.js";
33
import { $ZodRegistry, globalRegistry } from "./registries.js";
44
import type * as schemas from "./schemas.js";
5+
import { getEnumValues } from "./util.js";
56

67
interface JSONSchemaGeneratorParams {
78
/** A registry used to look up metadata for each schema. Any schema with an `id` property will be extracted as a $def.
@@ -400,7 +401,11 @@ export class JSONSchemaGenerator {
400401
}
401402
case "enum": {
402403
const json: JSONSchema.BaseSchema = _json as any;
403-
json.enum = Object.values(def.entries);
404+
const values = getEnumValues(def.entries);
405+
// Number enums can have both string and number values
406+
if (values.every((v) => typeof v === "number")) json.type = "number";
407+
if (values.every((v) => typeof v === "string")) json.type = "string";
408+
json.enum = values;
404409
break;
405410
}
406411
case "literal": {

packages/zod/src/v4/core/util.ts

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -203,13 +203,12 @@ export function assertNever(_x: never): never {
203203
}
204204
export function assert<T>(_: any): asserts _ is T {}
205205

206-
export function getValidEnumValues(obj: any): any {
207-
const validKeys = Object.keys(obj).filter((k: any) => typeof obj[obj[k]] !== "number");
208-
const filtered: any = {};
209-
for (const k of validKeys) {
210-
filtered[k] = obj[k];
211-
}
212-
return Object.values(filtered);
206+
export function getEnumValues(entries: EnumLike): EnumValue[] {
207+
const numericValues = Object.values(entries).filter((v) => typeof v === "number");
208+
const values = Object.entries(entries)
209+
.filter(([k, _]) => numericValues.indexOf(+k) === -1)
210+
.map(([_, v]) => v);
211+
return values;
213212
}
214213

215214
export function joinValues<T extends Primitive[]>(array: T, separator = "|"): string {

0 commit comments

Comments
 (0)