How to properly type a React ErrorBoundary class component in Typescript?

cbdeveloper picture cbdeveloper · Sep 16, 2020 · Viewed 7.2k times · Source

Here is my current attempt on how to properly type a React ErrorBoundary class component in Typescript:

import React from "react";
import ErrorPage from "./ErrorPage";
import type { Store } from "redux";   // I'M PASSING THE REDUX STORE AS A CUSTOM PROP

interface Props {
  store: Store         // THIS IS A CUSTOM PROP THAT I'M PASSING
}

interface State {      // IS THIS THE CORRECT TYPE FOR THE state ?
  hasError: boolean
}

class ErrorBoundary extends React.Component<Props,State> {
  
  constructor(props: Props) {
    super(props);
    this.state = { hasError: false };
  }

  static getDerivedStateFromError(error): State {
    // Update state so the next render will show the fallback UI.
    return { hasError: true };
  }

  componentDidCatch(error, errorInfo: React.ErrorInfo): void {
    // You can also log the error to an error reporting service
    // logErrorToMyService(error, errorInfo);
    console.log("error: " + error);
    console.log("errorInfo: " + JSON.stringify(errorInfo));
    console.log("componentStack: " + errorInfo.componentStack);
  }

  render(): React.ReactNode {
    if (this.state.hasError) {
      // You can render any custom fallback UI
      return(
        <ErrorPage
          message={"Something went wrong..."}
        />
      );
    }

    return this.props.children;
  }
}

export default ErrorBoundary;

This question is about the types for this ErrorBoundary class component. I'm breaking it into parts to make it easier.


PART A: Types for props and state

Is what I'm doing right?

interface Props {
  store: Store         // THIS IS A CUSTOM PROP THAT I'M PASSING
}

interface State {      // IS THIS THE CORRECT TYPE FOR THE state ?
  hasError: boolean
}

class ErrorBoundary extends React.Component<Props,State> {}

PART B: getDerivedStateFromError(error)

What type should I choose for the error parameter? The return type should be the State type, right?

static getDerivedStateFromError(error): State {
    // Update state so the next render will show the fallback UI.
    return { hasError: true };
  }

PART C: componentDidCatch(error, errorInfo: React.React.ErrorInfo)

What type should I choose for the error parameter? For the errorInfo, React does have a ErrorInfo type that seems to be correct. Is it? The return type should be void, correct?

componentDidCatch(error, errorInfo: React.ErrorInfo): void {
    console.log("error: " + error);
    console.log("errorInfo: " + JSON.stringify(errorInfo));
    console.log("componentStack: " + errorInfo.componentStack);
}

PART D: the render() method

Should the return type be ReactNode ?

render(): React.ReactNode {
    if (this.state.hasError) {
      // You can render any custom fallback UI
      return(
        <ErrorPage
          message={"Something went wrong..."}
        />
      );
    }

    return this.props.children;
  }

Answer

St&#233;phane Veyret picture Stéphane Veyret · Sep 16, 2020

You will get all your answers in the file index.d.ts from @types/react. If you are using an IDE like VSCode, you can Ctrl+click on a type to directly go to its definition.

Here is the precise answers to your questions, but before, let me advise you to prefer using react hooks instead of classes.


EDIT by OP: I never use class components, always prefer function and hooks, but from React docs on Error Boundaries:

Error boundaries work like a JavaScript catch {} block, but for components. Only class components can be error boundaries.


The lines I give are the one from index.d.ts in version 16.9.49.

Part A: yes, that's the way to do.

Part B: as you can see at line 658, error is of type any and the return type is a partial of the state or null.

Part C: at line 641, you will see that error is of type Error and return type is void.

Part D: at line 494, you can see that render should return a ReactNode