Struggling with defining types in NextJs when using dynamic imports in Typescript and NextJs

I have successfully created a component that utilizes next/dynamic to import react-icons only when needed. However, I am struggling to properly define the TypeScript types for this component. Despite this issue, the component itself is functioning as expected.

For those interested in viewing the TypeScript code, here is a link to the codesandbox: https://codesandbox.io/s/nextjs-dynamic-import-with-react-icons-zk1kz9

The code :

import dynamic from "next/dynamic";

const DynamicIcon = ({
  iconFamily,
  icon,
  ...rest
}: {
  iconFamily: keyof typeof Icons;
  icon: string;
}) => {
  const Icons = {
    // Dynamic imports for various icon families
  };

  const Icon = iconFamily && icon ? Icons[iconFamily] : null;

  if (!Icon) return <></>;

  return (
    <>
      <Icon {...rest} />
    </>
  );
};

export default DynamicIcon;

The error :

./components/DynamicIcon.tsx:12:17
Type error: Argument of type '() => Promise<typeof import("/sandbox/node_modules/react-icons/ci/index") | IconType | undefined>' is not assignable to parameter of type 'DynamicOptions<IconBaseProps> | Loader<IconBaseProps>'.
  Type '() => Promise<typeof import("/sandbox/node_modules/react-icons/ci/index") | IconType | undefined>' is not assignable to type '() => LoaderComponent<IconBaseProps>'.
    Type 'Promise<typeof import("/sandbox/node_modules/react-icons/ci/index") | IconType | undefined>' is not assignable to type 'LoaderComponent<IconBaseProps>'.
      Type 'typeof import("/sandbox/node_modules/react-icons/ci/index") |IconType | undefined' is not assignable to type 'ComponentType<IconBaseProps> | { default: ComponentType<IconBaseProps>; }'.
        Type 'undefined' is not assignable to type 'ComponentType<IconBaseProps> | { default: ComponentType<IconBaseProps>; }'.

I have attempted multiple methods of defining the type (such as strings or keyof typeof IconType), but have not yet found a solution.

Answer №1

"react-icons/*" is fetching components of type ReactComponent.

import { ComponentType } from "react";

type IconsType = { [key in typeof iconFamily]: ComponentType<any> };

const Icons: IconsType = {
    ci: dynamic(() => import("react-icons/ci").then((mod) => mod[icon])),
    ...
}

Answer №2

It seems like the problem lies in your use of returning a Promise in this section.

ci: dynamic(async () => {
    const mod = await import("react-icons/ci");
    return mod[icon];
})

Furthermore, you are passing the variable icon as a string, when it should actually be a value exported by the react-library. Consider defining an Enum type for the possible values of icon.

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

NextJS VSCode Typescript results in breakpoints becoming unbound

I have been following the instructions provided by Next.js from their official documentation on debugging using Visual Studio Code found here: https://nextjs.org/docs/advanced-features/debugging#using-the-debugger-in-visual-studio-code When attempting to ...

Obtain the present location of the cursor within the TinyMCE editor

Despite various attempts, I have struggled to determine the current cursor position inside TinyMCE. My goal is to implement a change control feature that captures the starting point of text entry within the TinyMCE "textarea," allowing me to save the ente ...

Is there a way to subscribe to various observables simultaneously in Angular 2, and then pause until fresh data is available on each of them?

I have an Angular component that relies on 3 services, each of which has an observer I can subscribe to. The view of the component needs to be updated whenever there are changes in the observed data, which occurs through websockets (feathers.js). I want th ...

Implementing Dynamic Component Rendering in React Native with Typescript

For the past 3 hours, I've been grappling with this particular issue: const steps = [ { Component: ChooseGameMode, props: { initialValue: gameMode, onComplete: handleChooseGameModeComplete } }, { Com ...

The declared type 'never[]' cannot be assigned to type 'never'. This issue is identified as TS2322 when attempting to pass the value of ContextProvider using the createContext Hook

I'm encountering an issue trying to assign the state and setState to the value parameter of ContextProvider Here's the code snippet:- import React, { useState, createContext } from 'react'; import { makeStyles } from '@material-ui ...

Props used in styled components are effective, although they may trigger a warning message stating, "Warning: Received `true` for a non-boolean attribute `cen`."

Caution: A non-boolean attribute "cen" received a value of "true". If you intend to render it in the DOM, provide a string instead: cen="true" or cen={value.toString()}. While using Props in Styled-Component with TypeScript and Material-UI, everything func ...

Changes in tabs are discarded when switching between them within Material UI Tabs

I have been experiencing an issue with the Material UI tab component where changes made in tabs are discarded when switching between them. It seems that after switching, the tabs are rendered again from scratch. For example, let's say I have a textFie ...

Having trouble with script tag not loading content in Next.js, even though it works perfectly fine in React

Currently, I am attempting to utilize a widget that I have developed in ReactJS by utilizing script tags as shown below- React Implementation import React from "react"; import { Helmet } from "react-helmet"; const Dust = () => { ...

Tips for extracting information from a TypeScript JSON document

Hey there, I'm currently having trouble understanding how to retrieve data from a JSON file. environment.ts: export const environment = { production: false, urlListBooks: "/assets/list-books.json", urlGetBooks: "/assets/edit- ...

All constructors at the base level must share a common return type

I am looking to convert my JSX code to TSX. I have a snippet that refactors a method from the react-bootstrap library: import {Panel} from 'react-bootstrap'; class CustomPanel extends Panel { constructor(props, context) { super(props ...

What is the process to subscribe and obtain data from a server-to-user channel using pusher-js?

I am currently hosting my application using next.js on Vercel. I want to integrate Pusher to provide real-time messages to users in a private and secure manner. Despite successful log entries, I am facing challenges in subscribing to the channel and retrie ...

Tips on dynamically looping the formcontrolname and implementing validation strategies

Looking for a way to validate multiple looping of dynamic formControlName="xxx" in select field. Check out my HTML code: <ul *ngFor="let detaillist of stressli.stresstabdetails;"> <li> <div class="form-container"> ...

The name 'Landbot' cannot be located. Have you meant to type '_landbot' instead?

I'm currently in the process of integrating Landbot into my React.js application with TypeScript. I'm following this [doc] 1. However, I'm facing an issue where the code inside useEffect (new Landbot.Container) is causing an error. 'C ...

Troubleshooting "Correctly specifying character set - Error!" in NextJS

My NextJS application contains both regular static pages and dynamically created static pages. Upon inspection, I noticed that both types of pages clearly define the <meta charset="utf-8"> tag, as shown in the screenshot. Strangely, while t ...

Obtain an instance tuple from tuple classes using TypeScript 3.0 generic rest tuples type

When it comes to retrieving the correct instance type from a class type, the process typically involves using the following code: type Constructor<T = {}> = new (...args: any[]) => T class Foo {} function getInstanceFromClass<T>(Klass: Co ...

Error TS2304: Unable to locate the word 'InputEvent'

While exploring the topic of whether TypeScript has type definitions for InputEvent, I experimented with using @types/dom-inputevent in my Angular 7 project. However, I kept encountering the error TS2304: Cannot find name 'InputEvent' whenever I ...

How can we fetch data from the server in Vue 2.0 before the component is actually mounted?

Can anyone help me with this question noted in the title? How can I prevent a component from mounting in <router-view> until it receives data from the server, or how can I fetch the data before the component is mounted in <router-view>? Here a ...

NextJS rewrites work seamlessly in a live environment

I recently implemented a method to rewrite requests to my backend server during development: https://nextjs.org/docs/api-reference/next.config.js/rewrites rewrites: async () => [ ...nextI18NextRewrites(localeSubpaths), { source: '/api/:path*' ...

How can you loop through an array of objects in TypeScript without relying on the traditional forEach

Currently, I'm working on an array of objects with the following structure. [ { "matListParent": "CH", "dParent": "CUST1", "isAllSelected": true, "childItems&qu ...

The React hook useState is struggling to accurately map array objects

Recently, I encountered an issue with a form that sends an array of objects to another React Functional Component: import React, { useState } from 'react' import uuid from 'uuid/v1'; const NewMovieForm = ( {addMovie }) => ...