Skip to content

Commit ab5b05b

Browse files
phryneasMichaelDeBoeytimdorrpcattori
authored andcommitted
feat(react-router): add SerializesTo brand type (#12264)
* Add `SerializesTo` brand type. * sign CLA * Update .changeset/sour-avocados-lick.md Co-authored-by: Michaël De Boey <[email protected]> * change `__RR_SerializesTo` to `__ReactRouter_SerializesTo` * mark `SerializesTo` as unstable --------- Co-authored-by: Michaël De Boey <[email protected]> Co-authored-by: Tim Dorr <[email protected]> Co-authored-by: Pedro Cattori <[email protected]>
1 parent 14690a1 commit ab5b05b

File tree

5 files changed

+44
-7
lines changed

5 files changed

+44
-7
lines changed

.changeset/sour-avocados-lick.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"react-router": patch
3+
---
4+
5+
Add `unstable_SerializesTo` brand type for library authors to register types serializable by React Router's streaming format (`turbo-stream`)

contributors.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,7 @@
246246
- pavsoldatov
247247
- pcattori
248248
- petersendidit
249+
- phryneas
249250
- phildl
250251
- pierophp
251252
- printfn

packages/react-router/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,7 @@ export type {
263263
FlashSessionData,
264264
} from "./lib/server-runtime/sessions";
265265

266+
export type { unstable_SerializesTo } from "./lib/types/serializes-to.ts";
266267
export type { Register } from "./lib/types/register";
267268
export { href } from "./lib/href";
268269

packages/react-router/lib/types/route-data.ts

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,15 @@ import type {
44
} from "../dom/ssr/routeModules";
55
import type { DataWithResponseInit } from "../router/utils";
66
import type { Serializable } from "../server-runtime/single-fetch";
7+
import type { unstable_SerializesTo } from "./serializes-to";
78
import type { Equal, Expect, Func, IsAny, Pretty } from "./utils";
89

910
// prettier-ignore
1011
type Serialize<T> =
11-
// First, let type stay as-is if its already serializable...
12+
// If type has a `SerializesTo` brand, use that type
13+
T extends unstable_SerializesTo<infer To> ? To :
14+
15+
// Then, let type stay as-is if its already serializable...
1216
T extends Serializable ? T :
1317

1418
// ...then don't allow functions to be serialized...
@@ -69,21 +73,38 @@ type __tests = [
6973
Expect<Equal<ServerDataFrom<any>, undefined>>,
7074
Expect<
7175
Equal<
72-
ServerDataFrom<() => { a: string; b: Date; c: () => boolean }>,
73-
{ a: string; b: Date; c: undefined }
76+
ServerDataFrom<
77+
() => {
78+
a: string;
79+
b: Date;
80+
c: () => boolean;
81+
d: unstable_SerializesTo<number>;
82+
}
83+
>,
84+
{ a: string; b: Date; c: undefined; d: number }
7485
>
7586
>,
7687
Expect<
7788
Equal<
7889
Pretty<
7990
ServerDataFrom<
8091
() =>
81-
| { json: string; b: Date; c: () => boolean }
82-
| DataWithResponseInit<{ data: string; b: Date; c: () => boolean }>
92+
| {
93+
json: string;
94+
b: Date;
95+
c: () => boolean;
96+
d: unstable_SerializesTo<number>;
97+
}
98+
| DataWithResponseInit<{
99+
data: string;
100+
b: Date;
101+
c: () => boolean;
102+
d: unstable_SerializesTo<number>;
103+
}>
83104
>
84105
>,
85-
| { json: string; b: Date; c: undefined }
86-
| { data: string; b: Date; c: undefined }
106+
| { json: string; b: Date; c: undefined; d: number }
107+
| { data: string; b: Date; c: undefined; d: number }
87108
>
88109
>,
89110
Expect<Equal<ServerDataFrom<() => { a: string } | Response>, { a: string }>>,
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
/**
2+
* A brand that can be applied to a type to indicate that it will serialize
3+
* to a specific type when transported to the client from a loader.
4+
* Only use this if you have additional serialization/deserialization logic
5+
* in your application.
6+
*/
7+
export type unstable_SerializesTo<T> = {
8+
unstable__ReactRouter_SerializesTo?: [T];
9+
};

0 commit comments

Comments
 (0)