Carl Rippon

Building SPAs

Carl Rippon
BlogBooks / CoursesAbout
This site uses cookies. Click here to find out more

React refs with TypeScript

November 18, 2020
reacttypescript

In this post, we cover how to use React refs with TypeScript in function and class components.

React Refs with TypeScript

Creating strongly-typed refs in function components

The useRef hook can be used to access all the properties and methods of an element.

const element = React.useRef(null);
// can access all the properties and methods of `element` via `element.current` 
...
return (
  <SomeElement ref={element} />
);

It is commonly used when we need to invoke methods on an element imperatively. Below is an example:

function Search() {
  const input = React.useRef(null);
  React.useEffect(() => {
    if (input.current) {
      input.current.focus();
    }
  }, []);
  return (
    <form>
      <input ref={input} type="search" />
    </form>
  );
};

We are setting focus on an input when the component first renders.

The type of input.current is inferred as null if strict mode is on; otherwise, it is inferred as any. A type error also occurs when input.current is referenced if strict mode is on.

Not ideal. 😞

We can explicitly define the type of the element returned from useRef by passing a generic type parameter:

const element = React.useRef<ElementType>(null);

So, we can explicitly type the ref in the Search component as follows:

const input = React.useRef<HTMLInputElement>(null);

The type error now disappears. πŸ˜ƒ

πŸƒ Play with the code

Creating strongly-typed refs in class components

Let’s implement the Search component as a class component. Below is a first attempt:

class Search extends React.Component {
  private input = React.useRef<HTMLInputElement>(null);
  
  componentDidMount() {
    if (this.input.current) {
      this.input.current.focus();
    }
  }
 
  render() {
    return (
      <form>
        <input ref={this.input} type="type" />
      </form>
    );
  }
}

The useRef hook can’t be used in class components though. 😞

In class components, we can get a reference to an element using createRef. We can use this to revise our implementation of the Search component:

class Search extends React.Component {
  private input = React.createRef(); 
  componentDidMount() {
    if (this.input.current) {
      this.input.current.focus();
    }
  }
 
  render() {
    return (
      <form>
        <input ref={this.input} type="type" />
      </form>
    );
  }
}

The type of the input element is inferred to be unknown though. This means we get a type error when this.input.current is referenced. 😞

We can explicitly define the type of the element returned from createRef by passing a generic type parameter:

React.createRef<ElementType>();

A revised, more strongly-typed version of the Search component is below.

class Search extends React.Component {
  private input = React.createRef<HTMLInputElement>(); 
  componentDidMount() {
    if (this.input.current) {
      this.input.current.focus();
    }
  }
 
  render() {
    return (
      <form>
        <input ref={this.input} type="type" />
      </form>
    );
  }
}

πŸƒ Play with the code

If we run the code, we will see that the focus is set on the input after it renders. πŸ˜ƒ

Did you find this post useful?

Let me know by sharing it on Twitter.
Click here to share this post on Twitter

If you to learn more about using TypeScript with React, you may find my course useful:

Using TypeScript with React

Find out more