PrehydrateAdvanced
TypeScript
Get autocomplete and catch errors early
Why TypeScript?
Prehydrate is built with TypeScript, which means your editor knows exactly what's happening. You get:
- Autocomplete — See available options as you type
- Error checking — Catch mistakes before you run your code
- Documentation — Hover over anything to see what it does
Tell Prehydrate your state type
Add a type parameter to prehydrate() and everything flows from there:
import { prehydrate } from 'prehydrate';
// Type-safe state
const { Prehydrate, bind } = prehydrate<Date>({
key: 'clock',
initialState: () => new Date(),
});Now TypeScript knows:
- Your
initialStatemust return aDate - The
bind()function returnsDatevalues - Your editor can warn you if something doesn't match
Typing your component props
When you pass bind to a component, you can type it for better autocomplete:
interface ClockProps {
bind: (key: string) => Record<string, Date | undefined>;
}
function Clock({ bind }: ClockProps) {
const [time, setTime] = useState<Date>(() => {
const boundProps = bind('time');
return boundProps.time || new Date();
});
// ...
}Or use the generic return type from prehydrate:
import { prehydrate, PrehydrateResult } from 'prehydrate';
const result: PrehydrateResult<Date> = prehydrate<Date>({
key: 'clock',
initialState: () => new Date(),
});Available types
If you need them, Prehydrate exports all its types:
import type {
PrehydrateOptions,
PrehydrateResult,
PrehydrateProps,
DependencyMap,
} from 'prehydrate';PrehydrateOptions<T>
interface PrehydrateOptions<T = unknown> {
key: string;
initialState?: T | (() => T);
deps?: DependencyMap;
}PrehydrateResult<T>
interface PrehydrateResult<T = unknown> {
Prehydrate: ComponentType<PrehydrateProps>;
bind: (key: string) => Record<string, T | undefined>;
}PrehydrateProps
interface PrehydrateProps {
children: ReactNode;
}DependencyMap
type DependencyMap = Record<string, unknown>;Typed helper functions
Your dependencies get type-checked too:
function formatTime(date: Date): string {
return date.toLocaleTimeString();
}
const { Prehydrate, bind } = prehydrate<Date>({
key: 'clock',
initialState: () => new Date(),
deps: {
formatTime,
},
});The types won't exist at runtime (dependencies become plain JavaScript), but they help catch mistakes while you're coding.
Putting it all together
import { prehydrate, PrehydrateResult } from 'prehydrate';
import { useState, useEffect, ReactElement } from 'react';
// Define state type
type TrafficLightState = 'red' | 'orange' | 'green';
// Helper function with types
function getLights(state: TrafficLightState) {
return [
{ color: 'red' as const, active: state === 'red' },
{ color: 'orange' as const, active: state === 'orange' },
{ color: 'green' as const, active: state === 'green' },
];
}
// Props interface
interface TrafficLightProps {
bind: (key: string) => Record<string, TrafficLightState | undefined>;
}
// Component with typed bind
function TrafficLight({ bind }: TrafficLightProps): ReactElement {
const [state, setState] = useState<TrafficLightState>(() => {
const boundProps = bind('state');
return boundProps.state || 'red';
});
useEffect(() => {
setState('green');
}, []);
const lights = getLights(state);
return (
<svg width="50" height="120">
{lights.map(({ color, active }, i) => (
<circle
key={color}
cx="25"
cy={25 + i * 35}
r="13"
fill={active ? color : '#555'}
/>
))}
</svg>
);
}
// Prehydrated wrapper with generic type
export function PrehydratedTrafficLight(): ReactElement {
const { Prehydrate, bind }: PrehydrateResult<TrafficLightState> =
prehydrate<TrafficLightState>({
key: 'traffic-light',
initialState: 'orange',
deps: { getLights },
});
return (
<Prehydrate>
<TrafficLight bind={bind} />
</Prehydrate>
);
}Project setup
Most TypeScript projects already have the settings Prehydrate needs:
{
"compilerOptions": {
"jsx": "react-jsx",
"esModuleInterop": true,
"moduleResolution": "node" // or "bundler"
}
}