0
# Type Definitions
1
2
Comprehensive type definitions for route modules, component props, and framework integration in Remix applications.
3
4
## Route Module Types
5
6
### Client Loader and Action Functions
7
8
```typescript { .api }
9
/**
10
* Function that loads data for a route on the client side
11
* Runs in the browser and can call server loader via serverLoader
12
*/
13
type ClientLoaderFunction = ((
14
args: ClientLoaderFunctionArgs
15
) => ReturnType<LoaderFunction>) & {
16
/** Whether to hydrate this loader on initial page load */
17
hydrate?: boolean;
18
};
19
20
/**
21
* Arguments passed to a route clientLoader function
22
*/
23
interface ClientLoaderFunctionArgs extends LoaderFunctionArgs {
24
/** Function to call the server loader */
25
serverLoader: <T = AppData>() => Promise<SerializeFrom<T>>;
26
}
27
28
/**
29
* Function that handles data mutations for a route on the client side
30
* Runs in the browser and can call server action via serverAction
31
*/
32
type ClientActionFunction = (
33
args: ClientActionFunctionArgs
34
) => ReturnType<ActionFunction>;
35
36
/**
37
* Arguments passed to a route clientAction function
38
*/
39
interface ClientActionFunctionArgs extends ActionFunctionArgs {
40
/** Function to call the server action */
41
serverAction: <T = AppData>() => Promise<SerializeFrom<T>>;
42
}
43
```
44
45
**Usage Examples:**
46
47
```typescript
48
import type { ClientLoaderFunction, ClientActionFunction } from "@remix-run/react";
49
50
// Client loader with server fallback
51
export const clientLoader: ClientLoaderFunction = async ({
52
params,
53
serverLoader
54
}) => {
55
// Try cache first
56
const cached = getCachedData(params.id);
57
if (cached) {
58
return cached;
59
}
60
61
// Fall back to server loader
62
const serverData = await serverLoader();
63
setCachedData(params.id, serverData);
64
return serverData;
65
};
66
67
// Client action with optimistic updates
68
export const clientAction: ClientActionFunction = async ({
69
request,
70
serverAction
71
}) => {
72
const formData = await request.formData();
73
74
// Optimistic update
75
updateUIOptimistically(formData);
76
77
try {
78
return await serverAction();
79
} catch (error) {
80
// Revert optimistic update
81
revertOptimisticUpdate();
82
throw error;
83
}
84
};
85
```
86
87
### Meta Function Types
88
89
```typescript { .api }
90
/**
91
* Function that returns meta descriptors for a route
92
* Used to generate meta tags in the document head
93
*/
94
type MetaFunction<
95
Loader = unknown,
96
ParentsLoaders = {}
97
> = (args: MetaArgs<Loader, ParentsLoaders>) => MetaDescriptor[];
98
99
/**
100
* Arguments passed to meta functions
101
*/
102
interface MetaArgs<Loader = unknown, ParentsLoaders = {}> {
103
/** Data from the route's loader */
104
data: SerializeFrom<Loader>;
105
/** Route parameters */
106
params: Params;
107
/** Current request object */
108
request: Request;
109
/** Current location */
110
location: Location;
111
/** Matched routes with their meta data */
112
matches: MetaMatches<ParentsLoaders>;
113
/** Error if the route threw */
114
error?: Error;
115
}
116
117
/**
118
* Individual meta descriptor types
119
*/
120
type MetaDescriptor =
121
| { title: string }
122
| { name: string; content: string }
123
| { property: string; content: string }
124
| { httpEquiv: string; content: string }
125
| { charset: string }
126
| { "script:ld+json": LdJsonObject }
127
| { tagName: "meta"; [key: string]: string }
128
| { tagName: string; [key: string]: unknown };
129
130
/**
131
* Meta matches from parent routes
132
*/
133
type MetaMatches<ParentsLoaders = {}> = Array<
134
MetaMatch<string, ParentsLoaders[keyof ParentsLoaders]>
135
>;
136
137
interface MetaMatch<
138
RouteId extends string = string,
139
Loader extends unknown = unknown
140
> {
141
id: RouteId;
142
pathname: string;
143
data: SerializeFrom<Loader>;
144
params: Params<string>;
145
meta: MetaDescriptor[];
146
}
147
```
148
149
**Usage Examples:**
150
151
```typescript
152
import type { MetaFunction } from "@remix-run/react";
153
154
export const meta: MetaFunction<typeof loader> = ({
155
data,
156
params,
157
location,
158
matches
159
}) => {
160
if (!data) {
161
return [{ title: "Not Found" }];
162
}
163
164
const parentMeta = matches.find(match => match.id === "root")?.meta || [];
165
166
return [
167
{ title: `${data.post.title} | My Blog` },
168
{ name: "description", content: data.post.excerpt },
169
{ property: "og:title", content: data.post.title },
170
{ property: "og:description", content: data.post.excerpt },
171
{ property: "og:image", content: data.post.imageUrl },
172
{ property: "og:url", content: `https://myblog.com${location.pathname}` },
173
...parentMeta.filter(meta => "name" in meta && meta.name === "author"),
174
];
175
};
176
```
177
178
### Route Component Types
179
180
```typescript { .api }
181
/**
182
* Main route component type
183
*/
184
type RouteComponent = ComponentType;
185
186
/**
187
* Error boundary component for route-level errors
188
*/
189
type ErrorBoundaryComponent = ComponentType;
190
191
/**
192
* Hydration fallback component for client loaders
193
*/
194
type HydrateFallbackComponent = ComponentType;
195
196
/**
197
* Layout component for root route
198
*/
199
type LayoutComponent = ComponentType<{
200
children: ReactElement<
201
unknown,
202
ErrorBoundaryComponent | HydrateFallbackComponent | RouteComponent
203
>;
204
}>;
205
206
/**
207
* Links function for route-level stylesheets and resources
208
*/
209
interface LinksFunction {
210
(): HtmlLinkDescriptor[];
211
}
212
213
/**
214
* Route handle for custom metadata
215
*/
216
interface RouteHandle {
217
[key: string]: any;
218
}
219
```
220
221
## Component Props Types
222
223
### Application Entry Point Props
224
225
```typescript { .api }
226
/**
227
* Props for RemixBrowser component
228
*/
229
interface RemixBrowserProps {
230
/** Base path for all routes */
231
basename?: string;
232
}
233
234
/**
235
* Props for RemixServer component
236
*/
237
interface RemixServerProps {
238
/** Entry context from server */
239
context: EntryContext;
240
/** Request URL */
241
url: string | URL;
242
/** Abort delay for deferred requests */
243
abortDelay?: number;
244
/** Nonce for CSP */
245
nonce?: string;
246
}
247
```
248
249
### Enhanced Component Props
250
251
```typescript { .api }
252
/**
253
* Props for enhanced Form component
254
*/
255
interface RemixFormProps extends Omit<FormHTMLAttributes<HTMLFormElement>, "onSubmit"> {
256
method?: "get" | "post" | "put" | "patch" | "delete";
257
action?: string;
258
discover?: "render" | "none";
259
encType?: "application/x-www-form-urlencoded" | "multipart/form-data" | "text/plain";
260
replace?: boolean;
261
preventScrollReset?: boolean;
262
reloadDocument?: boolean;
263
navigate?: boolean;
264
onSubmit?: (event: React.FormEvent<HTMLFormElement>) => void;
265
}
266
267
/**
268
* Props for enhanced Link component
269
*/
270
interface RemixLinkProps extends Omit<AnchorHTMLAttributes<HTMLAnchorElement>, "href"> {
271
to: string | Partial<Path>;
272
discover?: "render" | "none";
273
prefetch?: "none" | "intent" | "render" | "viewport";
274
replace?: boolean;
275
state?: any;
276
preventScrollReset?: boolean;
277
relative?: "route" | "path";
278
reloadDocument?: boolean;
279
unstable_viewTransition?: boolean;
280
}
281
282
/**
283
* Props for enhanced NavLink component
284
*/
285
interface RemixNavLinkProps extends RemixLinkProps {
286
className?: string | ((props: { isActive: boolean; isPending: boolean }) => string);
287
style?: CSSProperties | ((props: { isActive: boolean; isPending: boolean }) => CSSProperties);
288
children?: ReactNode | ((props: { isActive: boolean; isPending: boolean }) => ReactNode);
289
end?: boolean;
290
caseSensitive?: boolean;
291
}
292
293
/**
294
* Props for Await component
295
*/
296
interface AwaitProps<T> {
297
/** Promise to resolve */
298
resolve: Promise<T>;
299
/** Error boundary fallback */
300
errorElement?: ReactNode;
301
/** Children function that receives resolved value */
302
children: ReactNode | ((value: T) => ReactNode);
303
}
304
```
305
306
### Document Component Props
307
308
```typescript { .api }
309
/**
310
* Props for Scripts component
311
*/
312
interface ScriptProps {
313
/** Nonce for CSP */
314
nonce?: string;
315
/** Suppress hydration warnings */
316
suppressHydrationWarning?: boolean;
317
}
318
319
/**
320
* Props for ScrollRestoration component
321
*/
322
interface ScrollRestorationProps extends ScriptProps {
323
/** Function to generate storage key */
324
getKey?: (location: Location, matches: UIMatch[]) => string;
325
}
326
327
/**
328
* Props for LiveReload component (development only)
329
*/
330
interface LiveReloadProps {
331
/** Port for live reload server */
332
port?: number;
333
/** Reconnection timeout */
334
timeoutMs?: number;
335
/** Custom origin */
336
origin?: string;
337
/** Nonce for CSP */
338
nonce?: string;
339
}
340
```
341
342
## Link Descriptor Types
343
344
```typescript { .api }
345
/**
346
* HTML link descriptor for stylesheets and resources
347
*/
348
interface HtmlLinkDescriptor {
349
/** Link relationship */
350
rel: string;
351
/** Resource URL */
352
href?: string;
353
/** Media query */
354
media?: string;
355
/** MIME type */
356
type?: string;
357
/** Integrity hash */
358
integrity?: string;
359
/** Cross-origin policy */
360
crossOrigin?: "anonymous" | "use-credentials";
361
/** Referrer policy */
362
referrerPolicy?:
363
| ""
364
| "no-referrer"
365
| "no-referrer-when-downgrade"
366
| "same-origin"
367
| "origin"
368
| "strict-origin"
369
| "origin-when-cross-origin"
370
| "strict-origin-when-cross-origin"
371
| "unsafe-url";
372
/** Icon sizes */
373
sizes?: string;
374
/** Preload destination */
375
as?:
376
| "audio"
377
| "document"
378
| "embed"
379
| "fetch"
380
| "font"
381
| "image"
382
| "object"
383
| "script"
384
| "style"
385
| "track"
386
| "video"
387
| "worker";
388
/** Resource language */
389
hrefLang?: string;
390
}
391
392
/**
393
* Prefetch page descriptor
394
*/
395
interface PrefetchPageDescriptor {
396
/** Page path to prefetch */
397
page: string;
398
}
399
```
400
401
## Internal Types (UNSAFE)
402
403
These types are exported with UNSAFE_ prefix for advanced usage but may change in future versions.
404
405
```typescript { .api }
406
/**
407
* Future configuration flags
408
*/
409
interface FutureConfig {
410
unstable_singleFetch?: boolean;
411
unstable_fogOfWar?: boolean;
412
unstable_optimizeDeps?: boolean;
413
}
414
415
/**
416
* Assets manifest
417
*/
418
interface AssetsManifest {
419
version: string;
420
url: string;
421
entry: {
422
module: string;
423
imports: string[];
424
};
425
routes: Record<string, {
426
id: string;
427
parentId?: string;
428
path?: string;
429
index?: boolean;
430
caseSensitive?: boolean;
431
module: string;
432
imports?: string[];
433
hasAction: boolean;
434
hasLoader: boolean;
435
hasClientAction: boolean;
436
hasClientLoader: boolean;
437
hasErrorBoundary: boolean;
438
}>;
439
}
440
441
/**
442
* Remix context object
443
*/
444
interface RemixContextObject {
445
manifest: AssetsManifest;
446
routeModules: RouteModules;
447
serverHandoffString?: string;
448
abortDelay?: number;
449
serializeError: (error: Error) => SerializedError;
450
future: FutureConfig;
451
isSpaMode: boolean;
452
}
453
454
/**
455
* Entry route definition
456
*/
457
interface EntryRoute {
458
id: string;
459
parentId?: string;
460
path?: string;
461
index?: boolean;
462
caseSensitive?: boolean;
463
module: string;
464
imports?: string[];
465
hasAction: boolean;
466
hasLoader: boolean;
467
hasClientAction: boolean;
468
hasClientLoader: boolean;
469
hasErrorBoundary: boolean;
470
}
471
472
/**
473
* Route manifest
474
*/
475
type RouteManifest = Record<string, EntryRoute>;
476
```
477
478
## Utility Types
479
480
```typescript { .api }
481
/**
482
* Serialized form of data from loaders/actions
483
*/
484
type SerializeFrom<T> = T extends (...args: any[]) => infer R
485
? SerializeFrom<R>
486
: T extends Date
487
? string
488
: T extends object
489
? { [K in keyof T]: SerializeFrom<T[K]> }
490
: T;
491
492
/**
493
* UI match information
494
*/
495
interface UIMatch<T = unknown, Handle = RouteHandle> {
496
id: string;
497
pathname: string;
498
params: Params;
499
data: T;
500
handle: Handle | undefined;
501
}
502
503
/**
504
* Generic app data type
505
*/
506
type AppData = unknown;
507
508
/**
509
* Route discovery behavior options
510
* Controls when route modules should be discovered and loaded
511
*/
512
type DiscoverBehavior = "render" | "none";
513
514
/**
515
* Prefetch behavior options
516
* Controls when and how route data and assets should be prefetched
517
*/
518
type PrefetchBehavior = "intent" | "render" | "none" | "viewport";
519
520
/**
521
* Route parameters
522
*/
523
type Params<Key extends string = string> = {
524
readonly [key in Key]: string | undefined;
525
};
526
```
527
528
## Implementation Notes
529
530
- **Type Safety**: All types provide full TypeScript inference and safety
531
- **Serialization**: Types account for data serialization between server and client
532
- **Compatibility**: Types maintain compatibility with React Router and standard web APIs
533
- **Extensibility**: Route handles and context allow for custom type extensions
534
- **Future Flags**: Configuration types enable gradual adoption of new features
535
- **Error Handling**: Types include proper error state and boundary handling