I am using material-ui for a react app in typescript. material-ui provides withStyles which get injected into a component via its className. But I don't know how to declare its type. Below is an example code:

import * as React from 'react';
import Grid from '@material-ui/core/Grid';
import { withStyles, createStyles } from '@material-ui/core/styles';

const BackgroundPanelStyles = createStyles({
  root: {
    height: '16rem',
  }
});

const BackgroundPanelComponent = ({classes}: {classes: typeof BackgroundPanelStyles}) => {
  return (
    <Grid container className={classes.root}>

    </Grid>
  )
};

export const BackgroundPanel = withStyles(BackgroundPanelStyles)(BackgroundPanelComponent);

I defined the styles in BackgroundPanelStyles object and use that as component property type. But I got below errors. What is the correct way to define the property type in typescript?

 Argument of type '({ classes }: { classes: Record<"root", CSSProperties>; }) => Element' is not assignable to parameter of type 'ComponentType<ConsistentWith<{ classes: Record<"root", CSSProperties>; }, { classes: Record<"root", string>; }>>'.
  Type '({ classes }: { classes: Record<"root", CSSProperties>; }) => Element' is not assignable to type 'FunctionComponent<ConsistentWith<{ classes: Record<"root", CSSProperties>; }, { classes: Record<"root", string>; }>>'.
    Types of parameters '__0' and 'props' are incompatible.
      Type 'ConsistentWith<{ classes: Record<"root", CSSProperties>; }, { classes: Record<"root", string>; }> & { children?: ReactNode; }' is not assignable to type '{ classes: Record<"root", CSSProperties>; }'.
        Types of property 'classes' are incompatible.
          Type 'Record<"root", string>' is not assignable to type 'Record<"root", CSSProperties>'.
            Types of property 'root' are incompatible.
              Type 'string' is not assignable to type 'CSSProperties'.

2 Answers

0
Ranjan On

After some searching I find the props need to be interface Props { classes: { [className in keyof typeof BackgroundPanelStyles]: string } };

below code works as expected:

import * as React from 'react';
import Grid from '@material-ui/core/Grid';
import { withStyles, createStyles } from '@material-ui/core/styles';

const BackgroundPanelStyles = createStyles({
  root: {
    height: '16rem',
  }
});

interface Props { classes: { [className in keyof typeof BackgroundPanelStyles]: string } };

const BackgroundPanelComponent = ({ classes }: Props) => {
  return (
    <Grid container className={classes.root}>

    </Grid>
  )
};

export const BackgroundPanel = withStyles(BackgroundPanelStyles)(BackgroundPanelComponent);

0
henrik123 On

You can use the withStyles, WithStyles and StyleRulesCallback from @material-ui/core/styles to create a HOC. Read more about withstyles hoc here

Working demo here

import * as React from "react";
import Grid from "@material-ui/core/Grid";
import {
  StyleRulesCallback,
  withStyles,
  WithStyles
} from "@material-ui/core/styles";

export interface BackgroundPanelComponentOwnProps {
  someProp: Boolean;
}

export type withStyleProps = "someClass" | "anotherClass";
export type BackgroundPanelComponentStyleProps = WithStyles<withStyleProps>;
export type BackgroundPanelComponentProps = BackgroundPanelComponentOwnProps &
  BackgroundPanelComponentStyleProps;

const BackgroundPanelComponent: React.SFC<BackgroundPanelComponentProps> = props => {
  return (
    <Grid container={true} className={props.classes.someClass}>
      <Grid className={props.classes.anotherClass}>Hello</Grid>
    </Grid>
  );
};

const styles: StyleRulesCallback<withStyleProps> = () => ({
  someClass: {
    height: "16rem"
  },
  anotherClass: {
    color: "red"
  }
});

export const StyledBackgroundPanelComponent = withStyles(styles)(
  BackgroundPanelComponent
);