Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[system] component prop lost when wrapping with styled #29875

Open
2 tasks done
Brodzko opened this issue Nov 24, 2021 · 9 comments
Open
2 tasks done

[system] component prop lost when wrapping with styled #29875

Brodzko opened this issue Nov 24, 2021 · 9 comments
Labels
package: system Specific to @mui/system typescript

Comments

@Brodzko
Copy link

Brodzko commented Nov 24, 2021

Duplicates

  • I have searched the existing issues

Latest version

  • I have tested the latest version

Current behavior 😯

I discovered this while trying to override component for a styled ListSubheader in our app. I tried it for ListItem as well but not others - it seems that when wrapping a component with styled, the component prop is lost and TS errors out.

Expected behavior 🤔

component prop is not lost

Steps to reproduce 🕹

See codesandbox

Context 🔦

No response

Your environment 🌎

No response

@Brodzko Brodzko added the status: waiting for maintainer These issues haven't been looked at yet by a maintainer label Nov 24, 2021
@dantman
Copy link
Contributor

dantman commented Nov 25, 2021

This could have something to do with how styled() (along with memo and forwardRef) has a major issue in TypeScript with generic components being simplified to their defaults instead of kept as generic.

@hbjORbj hbjORbj added package: system Specific to @mui/system typescript and removed status: waiting for maintainer These issues haven't been looked at yet by a maintainer labels Nov 26, 2021
@mbrookes mbrookes changed the title component prop lost when wrapping with styled [system] component prop lost when wrapping with styled Nov 28, 2021
@jacten
Copy link

jacten commented Dec 4, 2021

@dantman is there an issue for that bug? I'm experiencing an issue when using styled on a 'div' where its children components are unmounting and wondering if it is related to that or I should create my own issue.

@zaandr
Copy link

zaandr commented Dec 15, 2021

I have a similar issue. After adding the "ref" property to the component, the component loses "component" property. But, the compiler doesn't swear.

const Test: React.VFC = (): ReactElement => {
    const ref = useRef(null);
    return <IconButton ref={ref} compo... />;  <-- does not offer
};

Or this is phpStorm problems... Does not offer this option from the list

@Myrnedraith
Copy link

I am also having this issue. Any word on when this might be resolved? I don't see an issue corresponding to the overall TypeScript generic loss problem.

@GuilleDF
Copy link
Contributor

Not sure if this helps narrow down the problem, but it seems that React.ComponentProps doesn't report the component prop for MUI components. From what I can see, styled uses React.ComponentProps internally.

import React from 'react';
import { SvgIcon } from '@mui/material';

type Props = React.ComponentProps<typeof SvgIcon>;
type IsComponentInProps = 'component' extends keyof Props ? true : false; // This should be `true`, but it's `false`

@wight554
Copy link

wight554 commented Apr 4, 2022

Can confirm this issue still exists in 5.4.4
Can be fixed this way, but it's definitely a bug:

export const SvgIcon = styled(MuiSvgIcon)<SvgIconProps & { component: ElementType }>(({ theme }) => ({
  marginRight: theme.spacing(0.5),
}));

@marconi1992
Copy link

Related #29191

@aimad-majdou
Copy link

In my case I fixed this by adding the prop component to the styled component:

const AutocompleteGroupLabelStyled = styled(ListSubheader, {
  name: 'AutocompleteMultiple',
  slot: 'GroupLabel',
  overridesResolver: (props, styles) => styles.groupLabel,
})<{ component: React.ElementType }>(({ theme }) => ({
  backgroundColor: theme.palette.background.paper,
  top: -8,
}));

@Sharlottes
Copy link

Sharlottes commented Jul 23, 2023

import type {
  OverridableComponent,
  OverridableTypeMap,
  OverrideProps,
} from "@mui/types";
import type { PropsOf, Theme } from "@emotion/react";
import type { StyledOptions } from "@emotion/styled";

/** @see https://github.com/mui/material-ui/issues/29875 */
declare module "@emotion/styled" {
  export interface CreateStyled {
    <
      CC extends React.ElementType,
      CM extends OverridableTypeMap,
      C extends OverridableComponent<CM>
    >(
      component: C,
      options?: StyledOptions<
        React.ComponentProps<C> & {
          component: CC;
        } & OverrideProps<CM, CC>
      >
    ): CreateStyledComponent<
      PropsOf<C> & {
        theme?: Theme;
      } & {
        component?: CC;
      } & OverrideProps<CM, CC>,
      {},
      {
        ref?: React.Ref<InstanceType<C>>;
      }
    >;
  }
}

image

I solved using module augmentation.

you can find CreateStyled declarations, which are the type of styled function in @mtoion/styled/types/base.
last one is about tag parameter(styled("div")({})), so excluded.
but I don't know about the first and third one which has the required options parameter.
because I don't use options parameter well, I augmented second one first.

/**
 * @desc
 * This function accepts a React component or tag ('div', 'a' etc).
 *
 * @example styled(MyComponent)({ width: 100 })
 * @example styled(MyComponent)(myComponentProps => ({ width: myComponentProps.width })
 * @example styled('div')({ width: 100 })
 * @example styled('div')<Props>(props => ({ width: props.width })
 */
export interface CreateStyled {
  <
    C extends React.ComponentClass<React.ComponentProps<C>>,
    ForwardedProps extends keyof React.ComponentProps<C> &
      string = keyof React.ComponentProps<C> & string
  >(
    component: C,
    options: FilteringStyledOptions<React.ComponentProps<C>, ForwardedProps>
  ): CreateStyledComponent<
    Pick<PropsOf<C>, ForwardedProps> & {
      theme?: Theme
    },
    {},
    {
      ref?: React.Ref<InstanceType<C>>
    }
  >

  <C extends React.ComponentClass<React.ComponentProps<C>>>(
    component: C,
    options?: StyledOptions<React.ComponentProps<C>>
  ): CreateStyledComponent<
    PropsOf<C> & {
      theme?: Theme
    },
    {},
    {
      ref?: React.Ref<InstanceType<C>>
    }
  >

  <
    C extends React.ComponentType<React.ComponentProps<C>>,
    ForwardedProps extends keyof React.ComponentProps<C> &
      string = keyof React.ComponentProps<C> & string
  >(
    component: C,
    options: FilteringStyledOptions<React.ComponentProps<C>, ForwardedProps>
  ): CreateStyledComponent<
    Pick<PropsOf<C>, ForwardedProps> & {
      theme?: Theme
    }
  >

  <C extends React.ComponentType<React.ComponentProps<C>>>(
    component: C,
    options?: StyledOptions<React.ComponentProps<C>>
  ): CreateStyledComponent<
    PropsOf<C> & {
      theme?: Theme
    }
  >

  <
    Tag extends keyof JSX.IntrinsicElements,
    ForwardedProps extends keyof JSX.IntrinsicElements[Tag] &
      string = keyof JSX.IntrinsicElements[Tag] & string
  >(
    tag: Tag,
    options: FilteringStyledOptions<JSX.IntrinsicElements[Tag], ForwardedProps>
  ): CreateStyledComponent<
    { theme?: Theme; as?: React.ElementType },
    Pick<JSX.IntrinsicElements[Tag], ForwardedProps>
  >

  <Tag extends keyof JSX.IntrinsicElements>(
    tag: Tag,
    options?: StyledOptions<JSX.IntrinsicElements[Tag]>
  ): CreateStyledComponent<
    { theme?: Theme; as?: React.ElementType },
    JSX.IntrinsicElements[Tag]
  >
}
  • I found this issue on joy-ui but whatever. mui and joy have the same style interface.

edit: i realized styled type from "@emotion/styled" and from "@mui/styled-engine" are different. below type is from "@mui/styled-engine", which import from "@mui/joy", not "@emotion/styled".

import type {
  OverridableComponent,
  OverridableTypeMap,
  OverrideProps,
} from "@mui/types";
import type { PropsOf } from "@emotion/react";
import type { StyledOptions } from "@emotion/styled";

/** @see https://github.com/mui/material-ui/issues/29875 */
declare module "@mui/styled-engine" {
  export interface CreateMUIStyled<
    MUIStyledCommonProps extends {},
    MuiStyledOptions,
    Theme extends object
  > {
    <
      CC extends React.ElementType,
      CM extends OverridableTypeMap,
      C extends OverridableComponent<CM>
    >(
      component: C,
      options?: StyledOptions<
        PropsOf<C> &
          MUIStyledCommonProps & {
            component: CC;
          } & OverrideProps<CM, CC>
      >
    ): CreateStyledComponent<
      PropsOf<C> &
        MUIStyledCommonProps & {
          component?: CC;
        } & OverrideProps<CM, CC>,
      {},
      {
        ref?: React.Ref<InstanceType<C>>;
      }
    >;
  }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
package: system Specific to @mui/system typescript
Projects
None yet
Development

No branches or pull requests