Skip to content

Commit 9157707

Browse files
krsilasKRAUSILedmundhung
authored
fix(conform-zod): type coercion for branded types (#864)
Co-authored-by: KRAUSIL <[email protected]> Co-authored-by: Edmund Hung <[email protected]>
1 parent 3ac7c51 commit 9157707

File tree

3 files changed

+94
-0
lines changed

3 files changed

+94
-0
lines changed

.changeset/early-buckets-complain.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@conform-to/zod': patch
3+
---
4+
5+
fix: type coercion with [branded](https://zod.dev/?id=brand) types (e.g. `z.string().brand()`)

packages/conform-zod/coercion.ts

+6
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import {
1313
lazy,
1414
any,
1515
ZodCatch,
16+
ZodBranded,
1617
} from 'zod';
1718
import type {
1819
ZodDiscriminatedUnionOption,
@@ -287,6 +288,11 @@ export function enableTypeCoercion<Schema extends ZodTypeAny>(
287288
]),
288289
),
289290
});
291+
} else if (def.typeName === 'ZodBranded') {
292+
schema = new ZodBranded({
293+
...def,
294+
type: enableTypeCoercion(def.type, cache),
295+
});
290296
} else if (def.typeName === 'ZodTuple') {
291297
schema = new ZodTuple({
292298
...def,

tests/conform-zod.spec.ts

+83
Original file line numberDiff line numberDiff line change
@@ -1253,6 +1253,89 @@ describe('conform-zod', () => {
12531253
reply: expect.any(Function),
12541254
});
12551255
});
1256+
1257+
test('z.brand', () => {
1258+
const schema = z
1259+
.object({
1260+
a: z.string().brand(),
1261+
b: z.number().brand(),
1262+
c: z.boolean().brand(),
1263+
d: z.date().brand(),
1264+
e: z.instanceof(File).brand(),
1265+
f: z.string().optional().brand(),
1266+
g: z.string().brand().optional(),
1267+
})
1268+
.brand();
1269+
expect(
1270+
parseWithZod(
1271+
createFormData([
1272+
['a', ''],
1273+
['b', ''],
1274+
['c', ''],
1275+
['d', ''],
1276+
['e', ''],
1277+
['f', ''],
1278+
['g', ''],
1279+
]),
1280+
{ schema },
1281+
),
1282+
).toEqual({
1283+
status: 'error',
1284+
payload: {
1285+
a: '',
1286+
b: '',
1287+
c: '',
1288+
d: '',
1289+
e: '',
1290+
f: '',
1291+
g: '',
1292+
},
1293+
error: {
1294+
a: ['Required'],
1295+
b: ['Required'],
1296+
c: ['Required'],
1297+
d: ['Required'],
1298+
e: ['Input not instance of File'],
1299+
},
1300+
reply: expect.any(Function),
1301+
});
1302+
const coercionTypesSchema = z.object({
1303+
a: z.string().brand(),
1304+
b: z.number().brand(),
1305+
c: z.boolean().brand(),
1306+
d: z.date().brand(),
1307+
e: z.bigint().brand(),
1308+
});
1309+
expect(
1310+
parseWithZod(
1311+
createFormData([
1312+
['a', 'hello world'],
1313+
['b', '42'],
1314+
['c', 'on'],
1315+
['d', '1970-01-01'],
1316+
['e', '0x1fffffffffffff'],
1317+
]),
1318+
{ schema: coercionTypesSchema },
1319+
),
1320+
).toEqual({
1321+
status: 'success',
1322+
payload: {
1323+
a: 'hello world',
1324+
b: '42',
1325+
c: 'on',
1326+
d: '1970-01-01',
1327+
e: '0x1fffffffffffff',
1328+
},
1329+
value: {
1330+
a: 'hello world',
1331+
b: 42,
1332+
c: true,
1333+
d: new Date('1970-01-01'),
1334+
e: BigInt('0x1fffffffffffff'),
1335+
},
1336+
reply: expect.any(Function),
1337+
});
1338+
});
12561339
});
12571340

12581341
test('parseWithZod with errorMap', () => {

0 commit comments

Comments
 (0)