Function that wraps JSX elements with the ability to infer types through generics

At the moment, this function is functioning properly

function wrapElement(elem: JSX.Element) {
  return ({ ...props }) => React.cloneElement(elem, { ...props })
}

I've been using it in this way to benefit from intelliSense for tailwind classes

const Btn = wrapElement(<button className="[A LOT OF TAILWIND UTILITY CLASSES]" />)

However, I'm attempting to modify it to return the same type as it receives so that I can have intelliSense for attributes on intrinsic HTML elements. Currently, the inferred type is

function wrapElement(elem: JSX.Element): ({ ...props }: {
    [x: string]: any;
}) => React.FunctionComponentElement<any>.FunctionComponentElement<any> 

I've tried various approaches, all resulting in errors. It seems like my current strategy may be too hacky, but maybe there's something I'm missing?

Answer №1

Obtaining the correct props from a JSX.Element is described as nearly impossible in this situation. To achieve the desired design, it is recommended to pass the element name and props as separate arguments instead of passing an entire JSX.Element.

This piece of code can handle an element name such as 'button' or any React component. It generates a function component with identical props. The returned component retains all props as it appears that the purpose is setting defaults rather than eliminating requirements.

import React, { ComponentType, ComponentProps } from "react";

const wrapElement = <
  C extends keyof JSX.IntrinsicElements | ComponentType<any>
>(
  Component: C,
  presetProps: Partial<ComponentProps<C>>
) => (props: ComponentProps<C>) => {
  const merged: ComponentProps<C> = { ...presetProps, ...props };
  return <Component {...merged} />;
};

const Btn = wrapElement("button", {
  className: "[A LOT OF TAILWIND UTILITY CLASSES]"
});

const Dbl = wrapElement(Btn, { onClick: () => alert("clicked") });

const Test = () => {
  return <Dbl>Click</Dbl>;
};

Typescript Playground Link

Consider customizing the merging behavior to blend className or style properties together rather than overriding them entirely.

Note: When attempting to merge props inline like

<Component {...presetProps} {...props} />
, an error was encountered stating "Type
Partial<ComponentProps<C>> & ComponentProps<C>
is not assignable to type
IntrinsicAttributes & LibraryManagedAttributes<C, any>
." This explains why the props are merged on a separate line and the type is explicitly annotated as ComponentProps<C> instead of the inferred type
Partial<ComponentProps<C>> & ComponentProps<C>
.

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

Is it possible to automatically correct all import statements in a TypeScript project?

After transferring some class member variables to a separate class in another file, I realized that these variables were extensively used in the project. As a result, approximately 1000 .ts files will need their imports modified to point to the new class/f ...

Tips for incorporating Mui Icon into the Content of pseudo elements (::after,::before) within a React component

Looking for a way to incorporate mui Icons using the pseudo Element "::before" with SX styling Below is the code snippet: import ArrowLeftIcon from "@mui/icons-material/ArrowLeft"; sx={{ "&.Mui-selected::before": { content: "ArrowLeftIcon", }, A ...

Creating a map-like scrolling feature for a full-sized image, allowing both horizontal and vertical movement

My goal is to create an infographic image that can be scrolled horizontally and vertically, zoomed in or out, and where I can add markers just like Google Maps. I attempted the solution of using two scroll views as suggested here: https://github.com/faceb ...

Is there a way for me to adjust the typography background based on its current status?

Is there a way to dynamically adjust the background color of text based on the status value? Currently, when the status is pending, the background color defaults to yellow. For example, if the status changes to complete, I want the background color to ch ...

When utilizing ng2-bootstrap, there is no directive that is defined with the "exportAs" attribute set to "bs-modal"

I found a tutorial that I am trying to emulate from this website However, when I insert the template into my HTML file <div class="modal fade" bsModal #staticModal="bs-modal" [config]="{backdrop: 'static'}" tabindex="-1" role="dialog" ...

Implement the addition of a numbering column to the MUI data table

I'm trying to figure out how to add a numbering column that displays the row index in my data table. Everything looks great except for the numbering, and I haven't found a solution yet. Here's my code: I have an action column with buttons: ...

Generate a dynamic key object in Angular/TypeScript

I am working with an object called "config" and an id named "id". My goal is to create an array of objects structured like this: [ "id" : { "config1: ... "config2: ... "config3: ... } "id2" : { "config ...

What is the best way to make two buttons align next to each other in a stylish and elegant manner

Currently, I am diving into the world of glamorous, a React component styling module. My challenge lies in styling two buttons: Add and Clear. The goal is to have these buttons on the same row with the Clear button positioned on the left and the Add button ...

How can I maintain form data submission to the server without triggering a redirect?

I am currently in the process of developing a web application that utilizes the Spotify API. My goal is to utilize the user input data to trigger calls to the Spotify API on the server and then relay the results back to the front end. However, I have encou ...

Is it necessary to conceal Angular navigation controls when the user is not authenticated?

In Angular, is there a standardized method for hiding controls when the user is not logged in? We already have the CanActivate guard which checks if a user can access a route. Would it be better to hide the route initially if the user is not logged in or l ...

unable to dynamically adjust distance using react ref

github: https://github.com/Brent-W-Anderson/shoe_store/tree/main Hello, I am facing an issue with utilizing react ref in my coding project. Specifically, I am working on developing an image slider and trying to center the first image in the set based on i ...

Returning a 404 Error stating "Invalid request to /api/users/register."

Encountering an issue with proxy connection - unable to determine the root cause despite verifying all routes. Not able to successfully register the user and store data in MongoDB. Seeking suggestions for resolution. Thank you. Attempting to send user reg ...

Typescript - Issue with accessing Express Response object

Having trouble using the methods of the Response object in my TypeScript method. When I try to log it, all I get is an empty object. It seems like the import is not providing the response as expected. import { Response } from 'express'; async sen ...

React with custom classes for Material UI Switch

I'm attempting to personalize the color of the toggle switch in Material UI using their classes props. I prefer not to use withStyles HOC because I am developing a customized Formik switch that can be utilized throughout my entire application. Howeve ...

Dealing with errors in getServerSideProps in Next.js by utilizing next-connect

Recently, I've been working with Next.js and utilizing the next-connect library to manage middlewares in my project. However, I'm encountering some difficulties when it comes to handling errors while using multiple middlewares within the getServ ...

Deactivate the rows within an Office UI Fabric React DetailsList

I've been attempting to selectively disable mouse click events on specific rows within an OUIF DetailsList, but I'm facing some challenges. I initially tried overriding the onRenderRow function and setting CheckboxVisibility to none, but the row ...

Angular version 5 and above introduces a new feature called "openFromComponent" within the Snackbar component, facilitating seamless communication

Angular (v5.2.10) Snackbar --| Introduction |-- I am facing a scenario where an Angular component named "Parent" is initializing an Angular Material Snackbar known as snackBar. The snackbar is being passed in the component called SnackbarMessage, which ...

Establishing a default selection for a react dropdown menu filled with data retrieved from an API request

class Select extends React.PureComponent { constructor(props) { super(props) this.state = { value: this.props.initialValue } this.handleChange = this.handleChange.bind(this) } handleChange(e) { e.persist() ...

Modify the card design when the screen is reduced in size and when the workspace is comprised of only two words

https://i.stack.imgur.com/jBqTE.png In my current project aimed at organizing tasks within companies, I am facing an issue with displaying a group of workspaces. The problem occurs when viewing the card changes its shape on a minimized screen, but only wh ...

Creating a shared singleton instance in Typescript that can be accessed by multiple modules

Within my typescript application, there is a Database class set up as a singleton to ensure only one instance exists: export default class Database { private static instance: Database; //Actual class logic removed public static getInstance() ...