@@ -172,24 +172,65 @@ const enumTypeToZodSchema = ({
172
172
} ) : Omit < ZodSchema , 'typeName' > => {
173
173
const result : Partial < Omit < ZodSchema , 'typeName' > > = { } ;
174
174
175
+ const zSymbol = plugin . referenceSymbol (
176
+ plugin . api . getSelector ( 'import' , 'zod' ) ,
177
+ ) ;
178
+
175
179
const enumMembers : Array < ts . LiteralExpression > = [ ] ;
180
+ const literalMembers : Array < ts . CallExpression > = [ ] ;
176
181
177
182
let isNullable = false ;
183
+ let allStrings = true ;
178
184
179
185
for ( const item of schema . items ?? [ ] ) {
180
- // Zod supports only string enums
186
+ // Zod supports string, number, and boolean enums
181
187
if ( item . type === 'string' && typeof item . const === 'string' ) {
182
- enumMembers . push (
183
- tsc . stringLiteral ( {
184
- text : item . const ,
188
+ const stringLiteral = tsc . stringLiteral ( {
189
+ text : item . const ,
190
+ } ) ;
191
+ enumMembers . push ( stringLiteral ) ;
192
+ literalMembers . push (
193
+ tsc . callExpression ( {
194
+ functionName : tsc . propertyAccessExpression ( {
195
+ expression : zSymbol . placeholder ,
196
+ name : identifiers . literal ,
197
+ } ) ,
198
+ parameters : [ stringLiteral ] ,
199
+ } ) ,
200
+ ) ;
201
+ } else if (
202
+ ( item . type === 'number' || item . type === 'integer' ) &&
203
+ typeof item . const === 'number'
204
+ ) {
205
+ allStrings = false ;
206
+ const numberLiteral = tsc . ots . number ( item . const ) ;
207
+ literalMembers . push (
208
+ tsc . callExpression ( {
209
+ functionName : tsc . propertyAccessExpression ( {
210
+ expression : zSymbol . placeholder ,
211
+ name : identifiers . literal ,
212
+ } ) ,
213
+ parameters : [ numberLiteral ] ,
214
+ } ) ,
215
+ ) ;
216
+ } else if ( item . type === 'boolean' && typeof item . const === 'boolean' ) {
217
+ allStrings = false ;
218
+ const booleanLiteral = tsc . ots . boolean ( item . const ) ;
219
+ literalMembers . push (
220
+ tsc . callExpression ( {
221
+ functionName : tsc . propertyAccessExpression ( {
222
+ expression : zSymbol . placeholder ,
223
+ name : identifiers . literal ,
224
+ } ) ,
225
+ parameters : [ booleanLiteral ] ,
185
226
} ) ,
186
227
) ;
187
228
} else if ( item . type === 'null' || item . const === null ) {
188
229
isNullable = true ;
189
230
}
190
231
}
191
232
192
- if ( ! enumMembers . length ) {
233
+ if ( ! literalMembers . length ) {
193
234
return unknownTypeToZodSchema ( {
194
235
plugin,
195
236
schema : {
@@ -198,22 +239,34 @@ const enumTypeToZodSchema = ({
198
239
} ) ;
199
240
}
200
241
201
- const zSymbol = plugin . referenceSymbol (
202
- plugin . api . getSelector ( 'import' , 'zod' ) ,
203
- ) ;
204
-
205
- result . expression = tsc . callExpression ( {
206
- functionName : tsc . propertyAccessExpression ( {
207
- expression : zSymbol . placeholder ,
208
- name : identifiers . enum ,
209
- } ) ,
210
- parameters : [
211
- tsc . arrayLiteralExpression ( {
212
- elements : enumMembers ,
213
- multiLine : false ,
242
+ // Use z.enum() for pure string enums, z.union() for mixed or non-string types
243
+ if ( allStrings && enumMembers . length > 0 ) {
244
+ result . expression = tsc . callExpression ( {
245
+ functionName : tsc . propertyAccessExpression ( {
246
+ expression : zSymbol . placeholder ,
247
+ name : identifiers . enum ,
214
248
} ) ,
215
- ] ,
216
- } ) ;
249
+ parameters : [
250
+ tsc . arrayLiteralExpression ( {
251
+ elements : enumMembers ,
252
+ multiLine : false ,
253
+ } ) ,
254
+ ] ,
255
+ } ) ;
256
+ } else {
257
+ result . expression = tsc . callExpression ( {
258
+ functionName : tsc . propertyAccessExpression ( {
259
+ expression : zSymbol . placeholder ,
260
+ name : identifiers . union ,
261
+ } ) ,
262
+ parameters : [
263
+ tsc . arrayLiteralExpression ( {
264
+ elements : literalMembers ,
265
+ multiLine : literalMembers . length > 3 ,
266
+ } ) ,
267
+ ] ,
268
+ } ) ;
269
+ }
217
270
218
271
if ( isNullable ) {
219
272
result . expression = tsc . callExpression ( {
0 commit comments