React Hooks in TypeScript
Released in React v16.8.0, React Hooks address a number of issues with React, and perhaps most notably for TypeScript users, provide a first-class solution for reusing stateful logic, built with typing in mind. Due to this, a lot of the types for Hooks can be inferred, but in some cases explicit types must be set.
This article assumes some knowledge of the Hooks that are available. For this refer to the React documentation.
In most cases, the types for
useState can be inferred based on the initial value, but if you need to start with
undefined, or need more control over the typing, such as specifying the types for an array or object, a generic can be used.
useContext can infer its types based on the context object that is passed in as an argument, so has no need for explicit typing.
useEffect / useLayoutEffect
These two hooks are used for performing side effects and return an optional clean up function. As they do not deal with returning values, no types are necessary.
useMemo / useCallback
useCallback (a shorthand for memoising functions) both have their types inferred from the values that they return.
Note: you must make sure you specify the types of the parameters of the callback for
useCallback, otherwise they will be set to
any, regardless of whether you have TypeScript’s
noImplicitAny set to true.
Historically, refs have been used for referencing DOM nodes or class components, with the ref object's readonly
current value starting as
null until the ref is attached. For this case
null can be used as the initial value and a generic can be used for the ref type:
Since the introduction of Hooks,
useRef can also be used as a replacement for instance properties on classes, in which case the type can be inferred and
current becomes mutable:
Reducers, the pattern introduced by Redux, can be typed in a similar fashion, with the types for the actions and state inferred from the reducer when supplied to
useImperativeHandle is by far the most involved Hook to set types for, but also likely the least used as it is not a common (or recommended) practice to expose imperative functions (handles) on components.
The above example wraps an HTML input component and exposes a
focus function in order to allow the input to be focussed. Firstly, an interface
MyInputHandles is declared to specify the functions that will be exposed through the ref. This interface is then passed to
RefForwardingComponent to set it up as a component that can have a ref passed to it, which is implemented using
forwardRef. From this,
useImperativeHandle can infer the types, so you will receive a compilation error if you do not implement the interface as the return value of the factory function in second argument.
The ref can then be used by using
MyInputHandles in the generic passed to
useDebugValue is used for displaying values in React Developer Tools and takes a value and an optional formatting function, for which the types can be inferred based on the value passed in.