Skip to content

Commit ec7caf7

Browse files
authored
Fix typeHint calculation for zod v4 (#71)
1 parent 9dcae47 commit ec7caf7

File tree

4 files changed

+59
-5
lines changed

4 files changed

+59
-5
lines changed

.yarn/versions/5ff6e18d.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
releases:
2+
react-router-typesafe-routes: patch

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [Unreleased]
9+
10+
### Fixed
11+
12+
- Zod string formats (e.g. `z.uuid()`) are now properly recognized as strings by the `zod()` helper.
13+
814
## [2.2.0] - 2025-07-20
915

1016
### Added
@@ -209,6 +215,7 @@ setTypedSearchParams((prevParams) => ({
209215
- Hook dependencies are now properly listed, which is checked by ESLint. This fixes `useTypedSearchParams` for dynamic routes.
210216
- Prevent access to internal `useUpdatingRef` helper.
211217

218+
[unreleased]: https://github.com/fenok/react-router-typesafe-routes/tree/dev
212219
[2.2.0]: https://github.com/fenok/react-router-typesafe-routes/tree/v2.2.0
213220
[2.1.0]: https://github.com/fenok/react-router-typesafe-routes/tree/v2.1.0
214221
[2.0.0]: https://github.com/fenok/react-router-typesafe-routes/tree/v2.0.0

src/lib/route.test.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1878,6 +1878,39 @@ it("allows to use zod v4", () => {
18781878
});
18791879
});
18801880

1881+
it("recognizes zod v4 string formats as strings", () => {
1882+
const TEST_ROUTE = route({
1883+
path: "",
1884+
1885+
searchParams: {
1886+
a: zod(z4.uuid()),
1887+
},
1888+
});
1889+
1890+
assert<
1891+
IsExact<
1892+
ReturnType<typeof TEST_ROUTE.$deserializeSearchParams>,
1893+
{
1894+
a?: string;
1895+
}
1896+
>
1897+
>(true);
1898+
1899+
const plainSearchParams = TEST_ROUTE.$serializeSearchParams({
1900+
searchParams: {
1901+
a: "6a5158f2-169a-4fbb-a3f2-0565774e59e4",
1902+
},
1903+
});
1904+
1905+
expect(urlSearchParamsToRecord(plainSearchParams)).toStrictEqual({
1906+
a: "6a5158f2-169a-4fbb-a3f2-0565774e59e4",
1907+
});
1908+
1909+
expect(TEST_ROUTE.$deserializeSearchParams(plainSearchParams)).toStrictEqual({
1910+
a: "6a5158f2-169a-4fbb-a3f2-0565774e59e4",
1911+
});
1912+
});
1913+
18811914
it("allows to use zod v3", () => {
18821915
const TEST_ROUTE = route({
18831916
path: "",

src/zod/zod.ts

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { type, Type, ParserHint, parser, Parser } from "../lib/index.js";
2-
import { ZodType, ZodOptional, ZodString, ZodDate, ZodNumber, ZodBoolean } from "zod/v4";
2+
import { ZodType, ZodOptional } from "zod/v4";
33
import {
44
ZodType as ZodTypeV3,
55
ZodOptional as ZodOptionalV3,
@@ -26,13 +26,25 @@ function configure({ parserFactory }: ConfigureOptions) {
2626

2727
let typeHint: ParserHint = "unknown";
2828

29-
if (unwrappedZodType instanceof ZodString || unwrappedZodType instanceof ZodStringV3) {
29+
if (
30+
(unwrappedZodType instanceof ZodType && unwrappedZodType.def.type === "string") ||
31+
unwrappedZodType instanceof ZodStringV3
32+
) {
3033
typeHint = "string";
31-
} else if (unwrappedZodType instanceof ZodNumber || unwrappedZodType instanceof ZodNumberV3) {
34+
} else if (
35+
(unwrappedZodType instanceof ZodType && unwrappedZodType.def.type === "number") ||
36+
unwrappedZodType instanceof ZodNumberV3
37+
) {
3238
typeHint = "number";
33-
} else if (unwrappedZodType instanceof ZodBoolean || unwrappedZodType instanceof ZodBooleanV3) {
39+
} else if (
40+
(unwrappedZodType instanceof ZodType && unwrappedZodType.def.type === "boolean") ||
41+
unwrappedZodType instanceof ZodBooleanV3
42+
) {
3443
typeHint = "boolean";
35-
} else if (unwrappedZodType instanceof ZodDate || unwrappedZodType instanceof ZodDateV3) {
44+
} else if (
45+
(unwrappedZodType instanceof ZodType && unwrappedZodType.def.type === "date") ||
46+
unwrappedZodType instanceof ZodDateV3
47+
) {
3648
typeHint = "date";
3749
}
3850

0 commit comments

Comments
 (0)