Tips for creating a Higher Order Component with TypeScript

My goal is to create a Higher Order Component (HOC) in TypeScript that takes an ErrorBoundary as input and returns the user's current location to be used within the ErrorBoundary component.

Here is the ErrorBoundary component:

import React from "react";

interface ErrorBoundaryProps {
  fallback: React.ReactNode;
  children: React.ReactNode;
  location: {
    pathname: string;
  };
}

class ErrorBoundary extends React.Component<ErrorBoundaryProps> {
  state = { hasError: false };

  static getDerivedStateFromError(error: Error) {
    return { hasError: true };
  }

  componentDidUpdate(previousProps: ErrorBoundaryProps) {
    if (previousProps.location.pathname !== this.props.location.pathname) {
      this.setState({ hasError: false });
    }
  }

  render() {
    if (this.state.hasError) {
      return this.props.fallback;
    }
    return this.props.children;
  }
}

export default ErrorBoundary;

And here is the WithRouter HOC:

import { useLocation } from "react-router-dom";

function WithRouter(OriginalComponent: React.ComponentType) {
  const NewComponent = (props: any) => {
    const location = useLocation();

    return <OriginalComponent {...props} location={location} />;
  };
  return NewComponent;
}

I am encountering issues with the TypeScript compiler and I have tried various solutions without success. In JavaScript, a similar implementation works fine:

import { useLocation } from "react-router-dom";

function WithRouter(OriginalComponent) {
  const NewComponent = (props) => {
    const location = useLocation();

    return <OriginalComponent location={location} {...props} />;
  };
  return NewComponent;
}

However, I am struggling to convert it to TypeScript.

Answer №1

One issue that stands out in the code is that React.ComponentType requires a parameter to be passed.

For instance:

function withRouter<P extends {}>(Component: React.ComponentType<P>) {
  const NewComponent = (props: any) => {
    const location = useLocation();

    return <Component {...props} location={location} />;
  };
  return NewComponent;
}

Alternatively,

const withRouter = <P extends {}>(Component: React.ComponentType<P>) => (
  props: any
) => {
  const location = useLocation();

  return <Component {...props} location={location} />;
};

Usage:

const ErrorBoundaryWithRouter = withRouter(ErrorBoundary);

It's recommended to utilize the Location type from React-Router-DOM for the ErrorBoundaryProps interface.

import type { Location } from "react-router-dom";

interface ErrorBoundaryProps {
  fallback: React.ReactNode;
  children: React.ReactNode;
  location: Location;
}

To improve accuracy, define the WithRouterProps as a distinct interface and extend it to create the ErrorBoundaryProps interface:

import type { Location } from "react-router-dom";

interface WithRouterProps {
  location: Location;
}

interface ErrorBoundaryProps extends WithRouterProps {
  fallback: React.ReactNode;
  children: React.ReactNode;
}

const withRouter = <P extends object>(Component: React.ComponentType<P>) => (
  props: Omit<P, keyof WithRouterProps>
) => {
  const location = useLocation();

  return <Component {...props as P} location={location} />;
};

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

There is no overload that matches this call within the context of React

Encountering an Error: D:/Downloads/Uber-Website-Clone-master/src/App.tsx TypeScript error in D:/Downloads/Uber-Website-Clone-master/src/App.tsx(17,7): No overload matches this call. Overload 1 of 2, '(props: Readonly): LoadScript', encountered ...

Is it possible for OpenFin to store logs in a secure database and what is the process for accessing logs located at %LocalAppData%openfinapps<app>app.log

System Information Here are the details of the system setup: OpenFin Process Manager Version: RVM = 8.1.0.4 Node.js: v16.15.0 Windows 10 Angular Application with C# .NET backend Issue: The current setup saves all application logs locally on users' ...

Encountering an Angular 13 ChunkLoadError during application deployment, despite the presence of the respective chunk

We encountered an issue with our application's upgrade from Angular 11 to 13. While running 'ng serve' on the local machine works fine, deploying it to our Azure app service causes the lazy loaded modules to fail loading. The specific error ...

Is there a solution to address the issue I am encountering with my API, specifically the 404 error that

I am currently developing an application that retrieves codes from a mongoDB database and displays them on a web page. However, I am encountering an issue in the console: GET http://localhost:4200/api/code/codes/ 404 (Not Found) zone.js:2863 This is a n ...

Is it possible for Visual Studio 2013 to compile TypeScript files even without node.js installed?

My current setup involves using TypeScript in combination with Visual Studio Code and the tsc CLI with node.js installed. I recently made an interesting discovery about tsc - I always assumed it was a javascript program, but then I started to wonder how ...

Exploring TypeScript interfaces with optional properties and returning types

As a newcomer to TypeScript, I am currently exploring the documentation and came across an example in the "Optional Properties" section that caught my attention: interface SquareConfig { color?: string; width?: number; } function createSquare(config: ...

What is the purpose of utilizing import and require() in Node.js programming?

Currently, I am analyzing the source code found at "Type definitions for Express 4.16" and stumbled upon this interesting line (#18): import serveStatic = require("serve-static"); I couldn't help but wonder why the above code is necessary or being u ...

The properties defined in the typescript model become inaccessible once the data is transferred to a different webpage

I've created a TypeScript model within my Angular application and initialized an object with that model. However, when passing the object through routing to the second component (UserComponent), the associated types are not available as shown in the i ...

What is the best way to trim a string property of an object within an array?

I am seeking a solution to access the "description" property of objects within an array and utilize a string cutting method, such as slice, in order to return an array of modified objects. I have attempted using for loops but have been unsuccessful. Here ...

Express server crashes when incorporating TypeScript alongside CRA

Summary I recently implemented Typescript into a Create React App (CRA) project, but I keep encountering the following error when attempting to serve the built application: SyntaxError: path\to\root\server\loader.js: Unexpected token, ...

The array within the JSON object holds vital information [Typescript]

I have some data stored in an Excel file that I want to import into my database. The first step was exporting the file as a CSV and then parsing it into a JSON object. fname,lname,phone Terry,Doe,[123456789] Jane,Doe,[123456788, 123456787] Upon convertin ...

Angular: Real-time monitoring of changes in the attribute value of a modal dialog and applying or removing a class to the element

I cannot seem to figure out a solution for the following issue: I have two sibling div elements. The second one contains a button that triggers a modal dialog with a dark overlay. However, in my case, the first div appears on top of the modal dialog due to ...

Building an array using class value types in TypeScript

Here is a sample class structure: export interface ILanguage { shortName: string; fullName: string; } export class Languages { static readonly FRENCH: ILanguage = { shortName: 'fr', fullName: 'FRENCH' }; static readonly DUTCH: I ...

What causes React to update the value of a read-only prop?

For this issue, I created a Codesandbox example. In the My App function, there is an array of objects called webItem. This webItem is passed as a property to the CreateWeb dialog window function. Within the code, I assign the webItem property to a variab ...

Leveraging the In-App Browser Cordova plugin in a TypeScript environment

Currently, I am facing a challenge while developing a Cordova app using TypeScript + React. I require the ability to open base64 images or PDF files in an external application such as Gallery or PDF Reader, allowing the user to choose their preferred opti ...

Save Component Characteristics in a type-safe array

Is it possible in Svelte to define a strongly typed array that matches the properties exported by a specific component? For instance, if I have the following code snippet, const things = [], is there a way for Svelte to recognize that each item within the ...

Filter an array of objects using criteria from a separate array [TypeScript/JavaScript]

I am faced with a scenario where I have two dropdowns, each designed to filter specific keys of an object. The key feature here is that the dropdown selections should not depend on each other; in other words, filtering can occur independently based on the ...

The npm script for running Protractor is encountering an error

Currently, I am facing an issue while trying to execute the conf.js file using an npm script. The conf.js file is generated within the JSFilesRepo/config folder after running the tsc command as I am utilizing TypeScript in conjunction with protractor-jasmi ...

In order to conceal the div tag once the animation concludes, I seek to implement React

I'm currently using the framer-motion library to add animation effects to my web page. I have a specific requirement where I want to hide a div tag used for animations once the animation is complete. Currently, after the animation finishes, the div t ...

Tips for adjusting the position of nodes that are overlapping in React Flow

Whenever node1 is moved over node2 in react-flow, they end up overlapping. I am looking to shift node2 towards the right to avoid this overlap. The desired outcome is for node2 to be shifted to the right side. ...