Transforming object destructuring from JavaScript to Typescript within an arrow function

I recently converted an arrow function destructure to Typescript, but I am struggling to understand the last item: icon: Icon. It seems that Icon is not imported or declared anywhere in the code.

Here is the original JavaScript:

const NavbarDropdown = ({
  children,
  count,
  showBadge,
  header,
  footer,
  icon: Icon
}) => (
  <UncontrolledDropdown nav inNavbar className="mr-2">
    <DropdownToggle nav className="nav-icon dropdown-toggle">
      <div className="position-relative">
        <Icon className="align-middle" size={18} />

I attempted to convert it to TypeScript, but encountered an error with {icon: Icon} since Icon was not imported or declared aside from within the function itself:

const NavbarDropdown = (
    {children} : {children: string},
    {count} : {count: number},
    {showBadge} : {showBadge: boolean},
    {header} : { header: string},
    {footer} : { footer: string},
    {icon: Icon},
  ) => (
    <UncontrolledDropdown nav inNavbar className="mr-2">
      <DropdownToggle nav className="nav-icon dropdown-toggle">
        <div className="position-relative">
          <Icon className="align-middle" size={18} />

Update: Despite understanding the discussion around Icon/icon, I still couldn't locate where Icon is imported or declared. Here's a snippet of the NavbarDropdown call:

  <Collapse navbar>
    <Nav className="ml-auto" navbar>
      <NavbarDropdown
        header="New Messages"
        footer="Show all messages"
        icon={MessageCircle}
        count={messages.length}
        showBadge
      >
        {messages.map((item, key) => {
          return (
            <NavbarDropdownItem
              key={key}
              icon={
                <img
                  className="avatar img-fluid rounded-circle"
                  src={item.avatar}
                  alt={item.name}
                />
              }
              title={item.name}
              description={item.description}
              time={item.time}
              spacing
            />
          );
        })}
      </NavbarDropdown>

Answer №1

Upon examination, two prominent issues have surfaced:

  1. The problem with the Icon.

  2. Misdefining the type of a single destructured parameter.

In relation to issue #1, it was stated:

During the conversion to TypeScript, an error arose with {icon: Icon} where Icon is not imported or declared anywhere except within the function's body.

In the JavaScript variant, the icon/Icon code segment appears as follows:

const NavbarDropdown = ({
  children,
  count,
  showBadge,
  header,
  footer,
  icon: Icon
}) => (

The icon: Icon section might resemble a TypeScript type declaration, but in reality, it serves as part of the destructuring process. It takes the value of the icon property from the object and assigns it to an identifier named Icon. In essence, it functions similarly to this scenario:

const NavbarDropdown = (props) => {
    let children = props.children;
    // ...
    let Icon = props.icon;

This allows the identifier to begin with an uppercase letter inside the function so that it can be utilized as a React component in JSX:

<Icon className="align-middle" size={18} />
(Using <icon .../> would create an HTML element instead of a React component.)

Regarding issue #2: Rather than individually typing each parameter during destructuring, the type should follow the curly braces {}:

const NavbarDropdown = ({
  children,
  count,
  showBadge,
  header,
  footer,
  icon: Icon
}: {
  children: string;
  count: number;
  showBadge: boolean;
  header: string;
  footer: string;
  icon: React.Component;
}) => (
  <UncontrolledDropdown nav inNavbar className="mr-2">
    <DropdownToggle nav className="nav-icon dropdown-toggle">
      <div className="position-relative">
        <Icon className="align-middle" size={18} />
        ...

An alternative approach involves defining a reusable type for clarity and consistency:

interface NavbarDropdownProps {
  children: string;
  count: number;
  showBadge: boolean;
  header: string;
  footer: string;
  icon: React.Component;
}
const NavbarDropdown = ({
  children,
  count,
  showBadge,
  header,
  footer,
  icon: Icon
}: NavbarDropdownProps) => (
  <UncontrolledDropdown nav inNavbar className="mr-2">
    <DropdownToggle nav className="nav-icon dropdown-toggle">
      <div className="position-relative">
        <Icon className="align-middle" size={18} />
        ...

When specifically typing a React functional component, React offers a helpful type called React.FunctionComponent or its abbreviated form React.FC, which is commonly preferred:

interface NavbarDropdownProps {
  children: string;
  count: number;
  showBadge: boolean;
  header: string;
  footer: string;
  icon: React.Component;
}

const NavbarDropdown: React.FC<NavbarDropdownProps> = ({
  children,
  count,
  showBadge,
  header,
  footer,
  icon: Icon
}) => (
  <UncontrolledDropdown nav inNavbar className="mr-2">
    <DropdownToggle nav className="nav-icon dropdown-toggle">
      <div className="position-relative">
        <Icon className="align-middle" size={18} />
        ...

It is important to note that by specifying the props type using a generic parameter with React.FC, there is no need to reiterate the types in the parameter list.

Typically, in a functional component, children should ideally be of type ReactNode rather than string. While utilizing string works due to ReactNode being a union type encompassing various data types, it limits the flexibility of acceptable child components.

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

Adding and adjusting the size of different DIV elements within a shared area

Looking to create a dynamic bar with the ability to add multiple child DIVs (similar to this: https://i.stack.imgur.com/tdWsq.jpg). Utilizing jQuery, jQuery UI, Bootstrap, and various plugins. The structure for the div (or span) system could be structured ...

Securing pathways and pages using NextJs

I recently completed a project where I implemented route protection for a website using the if and else statements, assigning each page a function withAuth(). However, I have concerns about whether this is the most effective method for securing routes in n ...

Ways to conceal the 'Return to Top' button in a script that is only revealed after navigating to the bottom of the page

Can anyone help me hide the 'Back to Top' button in a script that only appears after scrolling to the bottom of the page? I need to take screenshots without it showing up. I've tried using the code below, but the 'Back to Top' but ...

Moving an item to the top of an array in JavaScript/Vue.js: A simple guide

const a = [{ "iso2": "KH", "countryName": "Cambodia", "nationality": "Cambodian" }, { "iso2": "KI", "countryName": "Kiribati", "nationality": "I-Kiribati" }, { "iso2": "KM", "countryName": "Comoros", "nationality": "Como ...

skip every nth element in the array based on the specified value

The Challenge I'm currently working on a graph that relies on an array of data points to construct itself. One major issue I've encountered is the need for the graph to be resizable, which leads to the necessity of removing certain data points ...

Regular expression that matches a string with optional leading and trailing spaces and a hyphen in the middle

I need help creating a JavaScript regex that can match strings like the examples provided. The string may have whitespace at the front, back, or both but not within the string itself. Examples: 'Z5LW-KRT2' MATCH ' Z5LW-krt2' ...

Utilizing Vuetify in Typescript: Making Use of Data() Properties

ie data() { return { bar: false rules: { foo: (value) => { if (this.bar) {} } } } } The code is functioning correctly. What steps can be taken to help typescript comprehend this? If this is considered a " ...

Fixing the issue: "Tricky situation with JavaScript not working within Bootstrap 4's div tag while JS functions properly elsewhere"

Currently, I'm working on implementing a hide/show function for comments using JavaScript. Fortunately, I was able to find a helpful solution here (thanks to "PiggyPlex" for providing the solution on How can I hide/show a div when a button is clicked? ...

Learn how to transfer information via WebSocket when the connection closes in a React/NextJS application during a page reload or tab

In the development of my web application, I am implementing a feature to display the online/offline status of users. In order to achieve this functionality, I have to listen for both close and open events of the websocket. const ws = new WebSocket('ws ...

Tips for specifying a variable as a mandatory key attribute within an array

Is there a way to dynamically determine the type of key attribute in an array? const arr = [ { key: 'a' }, { key: 'b' }, { key: 'c' }, ]; type key = ??? // Possible values for key are 'a', 'b', or &a ...

"Seeking a more flexible JSON parser that allows for greater

I am in need of passing various strings that are formatted as json to a json parser. The issue is that jQuery.parseJSON() and JSON.parse() strictly support only a specific json format: If a malformed JSON string is passed, an exception may be thrown. For ...

Update the input value with the selected option from the dropdown menu in Angular

How can I dynamically set the value of an input field based on the selection from a dropdown menu in Angular using Reactive Forms? Below is my HTML code: <nb-card> <nb-card-header> Services </nb-card-header> <nb-card-body&g ...

Tips for changing the meta details with real-time records in Vue.js using vue-meta

I am experiencing an issue with updating meta descriptions using vue-meta in my articles. Despite attempting to fetch information from my API using async and mounted properties, the default meta descriptions set by Vue js are still being displayed instead ...

What is the reason behind only the final input value being shown on the screen?

I'm encountering an issue with my input fields. I have a total of five input fields. After filling all of them and clicking the button to display them on the screen, only the last one I entered is shown in all places... (let me know if this explanatio ...

Interacting with MongoDB in a React application using Redux and Redux Thunk

Welcome to the Mock Library website, where you can view books (author title genre) from the database and even add a new book. After checking, it appears that the data is properly fetched from my react component. It is then passed on correctly to the actio ...

Utilizing Jquery for Mouse Clicks

Is there a way to simulate a mouse click using jQuery? <div id="myId> Simulate Mouse Click programatically</div> I currently have a mouse listener set up. $("#myId").mousedown(function(){ alert("Mouse clicked programatically"); }) ...

Utilizing the power of AWS Lambda in conjunction with moment JS to generate unique

My current time zone is GMT+8, and the AWS region I am using is Singapore (ap-southeast-1). I am facing an issue where there are discrepancies in date calculations between my local machine and when I deploy my code on AWS Lambda. My goal is to ensure that ...

Restrain a Key according to the data type of its value within a universal category

I am currently working on creating a versatile function where the generic type is used to define its parameter. Here's an excerpt from this parameter : type Configuration<T> = { masterdata: T[], target: ???? } I am encountering difficu ...

The 'clientX' property is not recognized on the 'Event' type in Angular2 Directive

When attempting to retrieve the X position of my mouse in an Angular2 Directive using the following code: @HostListener('mousemove', ['$event']) onMousemove(event: Event): void { console.log(event.clientX) } I encountered an error ...

Using jQuery to add an element at the current caret position

Within my contentEditable div, there is a table nested. Here is an example of the HTML structure: <div id="divId" contenteditable="true"> <table> <tbody> <tr> <td><br></td> ...