Typing built-in React hooks
useState
const [amount, setAmount] = useState<number | string>(3);
With a ustom type
interface IState {
people: IPerson[];
}
interface IPerson {
name: string;
age: number;
}
const [people, setPeople] = useState<IState>({});
// Alternative declaration
interface IState {
people: {
name: string;
age: number;
}[];
}
const [people, setPeople] = useState<IState["people"]>({});
useReducer
Mostly the same. They key thing to type is the reducer function itself. You don’t need to type the intitial state unless it is a pre-existing type, you can just use type assertion:
interface IAction {
| { type: "increment"; payload: number }
| { type: "decrement"; payload: string };
}
const initialState = { count: 0 };
function reducer(state: typeof initialState, action: IAction) {
switch (action.type) {
case "increment":
return { count: state.count + action.payload };
case "decrement":
return { count: state.count - Number(action.payload) };
default:
throw new Error();
}
}
Then the syntax is as normal, i.e:
const [state, dispatch] = useReducer(reducer, initialState);
useEffect
Limited potential for typing here as this hook does not return a value. See if there is useful inferred typing from use and update.
useContext
We can use generics but mostly this is untyped:
type Theme = "light" | "dark";
const ThemeContext = createContext < Theme > "dark";
const App = () => (
<ThemeContext.Provider value="dark">
<MyComponent />
</ThemeContext.Provider>
);
const MyComponent = () => {
const theme = useContext(ThemeContext);
return <div>The theme is {theme}</div>;
};
useCallback
/ useMemo
You must only type the parameters that are passed to the callback, the return value will be inferred.