React Hooks in TypeScript

James Ravenscroft
3 min readFeb 13, 2019

--

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.

useState

In most cases, the types for useState can be inferred based on the initial value, but if you need to start with null or undefined, or need more control over the typing, such as specifying the types for an array or object, a generic can be used.

useContext

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

Both useMemo and 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.

useRef

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:

useReducer

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 useReducer:

useImperativeHandle

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 useRef:

useDebugValue

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.

--

--

James Ravenscroft

Web developer currently working with TypeScript, React and Node in Auckland, New Zealand.