Skip to content

Commit 03b3c0b

Browse files
authored
fix and tests for #2427 (#2498)
1 parent 1da0c2d commit 03b3c0b

File tree

2 files changed

+97
-0
lines changed

2 files changed

+97
-0
lines changed

packages/zod/src/index.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,17 @@ export const generateZodValidationSchemaDefinition = (
257257
rawStringified === undefined
258258
? 'null'
259259
: rawStringified.replaceAll("'", '"');
260+
261+
// If the schema is an array with enum items, add 'as const' for proper TypeScript typing
262+
const isArrayWithEnumItems =
263+
Array.isArray(schema.default) &&
264+
type === 'array' &&
265+
schema.items &&
266+
'enum' in schema.items;
267+
268+
if (isArrayWithEnumItems) {
269+
defaultValue = `${defaultValue} as const`;
270+
}
260271
}
261272
consts.push(`export const ${defaultVarName} = ${defaultValue};`);
262273
}

packages/zod/src/zod.test.ts

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -896,6 +896,92 @@ describe('generateZodValidationSchemaDefinition`', () => {
896896
"zod.union([zod.literal('cat'),zod.literal(1),zod.literal(true)]).optional()",
897897
);
898898
});
899+
900+
it('generates a default value for an array with enum items using "as const"', () => {
901+
const schemaWithEnumArrayDefault: SchemaObject30 = {
902+
type: 'array',
903+
items: {
904+
type: 'string',
905+
enum: ['A', 'B', 'C'],
906+
},
907+
default: ['A'],
908+
};
909+
910+
const result = generateZodValidationSchemaDefinition(
911+
schemaWithEnumArrayDefault,
912+
context,
913+
'testEnumArrayDefault',
914+
false,
915+
false,
916+
{ required: false },
917+
);
918+
919+
expect(result).toEqual({
920+
functions: [
921+
[
922+
'array',
923+
{
924+
functions: [['enum', "['A', 'B', 'C']"]],
925+
consts: [],
926+
},
927+
],
928+
['default', 'testEnumArrayDefaultDefault'],
929+
],
930+
consts: ['export const testEnumArrayDefaultDefault = ["A"] as const;'],
931+
});
932+
933+
const parsed = parseZodValidationSchemaDefinition(
934+
result,
935+
context,
936+
false,
937+
false,
938+
false,
939+
);
940+
expect(parsed.zod).toBe(
941+
"zod.array(zod.enum(['A', 'B', 'C'])).default(testEnumArrayDefaultDefault)",
942+
);
943+
expect(parsed.consts).toBe(
944+
'export const testEnumArrayDefaultDefault = ["A"] as const;',
945+
);
946+
});
947+
948+
it('generates a default value for nested enum arrays in objects', () => {
949+
const schemaWithNestedEnumArray: SchemaObject30 = {
950+
type: 'object',
951+
properties: {
952+
some_enum: {
953+
type: 'array',
954+
items: {
955+
type: 'string',
956+
enum: ['A', 'B', 'C'],
957+
},
958+
default: ['A'],
959+
},
960+
},
961+
};
962+
963+
const result = generateZodValidationSchemaDefinition(
964+
schemaWithNestedEnumArray,
965+
context,
966+
'postEnumBody',
967+
false,
968+
false,
969+
{ required: false },
970+
);
971+
972+
expect(result.functions[0][0]).toBe('object');
973+
974+
// Check that the nested array default has 'as const'
975+
const objectProperties = result.functions[0][1] as Record<
976+
string,
977+
ZodValidationSchemaDefinition
978+
>;
979+
const someEnumProperty = objectProperties['some_enum'];
980+
981+
expect(someEnumProperty.consts).toEqual(
982+
expect.arrayContaining([expect.stringContaining('as const')]),
983+
);
984+
});
899985
});
900986
describe('number handling', () => {
901987
const context: ContextSpecs = {

0 commit comments

Comments
 (0)