Material-ui: [typescript] components loose component prop with emotion or styled-component

Created on 14 May 2019  路  7Comments  路  Source: mui-org/material-ui


When using styled components >=4.1.0 or emotion >=10 there will be type errors if material ui components are styled.

  • [x] This is not a v0.x issue.
  • [x] I have searched the issues of this repository and believe that this is not a duplicate.

Expected Behavior 馃


No build or type errors are expected when styling material ui components with styled components or emotion.

Current Behavior 馃槸


A lot of type errors like

TS2740: Type '{ children: string; }' is missing the following properties from type 'Pick<Pick<(Pick<PaperProps, "style" | "title" | "children" | "className" | "color" | "id" | "lang" | "role" | "tabIndex" | "elevation" | "aria-activedescendant" | "aria-atomic" | ... 245 more ... | "innerRef"> & RefAttributes<...>) | PropsWithChildren<...>, "ref
" | ... 257 more ... | "innerRef"> & Partial<...>, "ref...': ref, style, title, className, and 254 more.

or

TS2322: Type '{ children: Element; component: string; }' is not assignable to type 'IntrinsicAttributes & Pick<Pick<DefaultComponentProps<{ props: { dense?: boolean | undefined; disablePadding?: boolean | undefined; subheader?: ReactElement<any, string | ((props: any) => ReactElement<any, string | ... | (new (props: any) => Component<...>)> | n
ull) | (new (props: any) => Component<...>)> | undefine...'.
  Property 'component' does not exist on type 'IntrinsicAttributes & Pick<Pick<DefaultComponentProps<{ props: { dense?: boolean | undefined; disablePadding?: boolean | undefined; subheader?: ReactElement<any, string | ((props: any) => ReactElement<any, string | ... | (new (props: any) => Component<...>)> | null) | (new (props: any) => Component<...>)
> | undefine...'.

Steps to Reproduce 馃暪

  1. Checkout https://github.com/Mario-Eis/materialui-styled-test and npm install
  2. Run npm script 'serve-dev' --> localhost:3000
  3. Build errors are readable in the console.

I don't know for sure, but I think there could be two different issues in the demo.
The first is a simple styled Paper component. When downgrading to styled components <=4.0.3, this issue will be fixed.
The second one is a styled List component. Styled List components will work, as long as there are no prop attributes set. If e.g. component="nav" is added, there will be an error. Downgrading to styled-components 4.0.3 won't work here. But downgrading to material ui 3.9.2, will.

Both cases are shown in the demo.

Context 馃敠


I want to style material ui components using styled-components library.

Your Environment 馃寧

| Tech | Version |
|--------------|---------|
| Material-UI |4.0.0 |
| React |16.8.17|
| TypeScript |3.4.5|

external dependency typescript wontfix

Most helpful comment

@oliviertassinari why shouldn't the workaround be part of MUI itself though?

All 7 comments

This is a limitation of typescript. See https://github.com/mui-org/material-ui/issues/15759#issuecomment-493994852 for the recommended solution i.e. casting the wrapped component back to the original type. I understand this is not ideal but there are other limitations in typescript that block other approaches. For these simple applications where props available from the HOC are of no interest type casting seems good enough. For more complex examples follow #15827 which should have a proposal by the end of this week.

Casting back to the original type would be possible. But its a hard change. We have a large code base. And adding casts to each and every component could break the upgrade for us.

I also tried to implement the type cast to the demo under https://github.com/Mario-Eis/materialui-styled-test.

The good news: The issue shown in the demo with the Paper Component, seems to be fixed.

Unfortunately

const StyledList = styled(List)`
    background-color: blue;
    text-align: center;
` as List;

results in

TS2749: 'List' refers to a value, but is being used as a type here.

I pushed the workaround to the demo repo.

List is now defined as a variable.

declare const List: OverridableComponent<{
  props: {
    dense?: boolean;
    disablePadding?: boolean;
    subheader?: React.ReactElement;
  };
  defaultComponent: 'ul';
  classKey: ListClassKey;
}>;

The workaround doesn't seem to work any more.

const StyledList = styled(List)`
    background-color: blue;
    text-align: center;
` as typeof List;

Seems codemodable. Though you have to be aware that any type information about props handled by styled is lost.

Thanks! I updated the demo repo. It compiles without errors now.
Only the IDE (IntelliJ) shows a warning that there is a missing required attribute "component". But I think that will be another issue. Will investigate that.

@Mario-Eis
Hello.
This should help:

const StyledList = styled<ComponentType<ListProps>>(List)`
    background-color: blue;
    text-align: center;
`;

Closing as it was labeled as a limitation of TypeScript and has a workaround.

@oliviertassinari why shouldn't the workaround be part of MUI itself though?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

activatedgeek picture activatedgeek  路  3Comments

pola88 picture pola88  路  3Comments

reflog picture reflog  路  3Comments

iamzhouyi picture iamzhouyi  路  3Comments

ghost picture ghost  路  3Comments