0
votes

I am getting increasingly frustrated as I have spent the past couple of days trying to migrate my react application from javascript to tsx. So far I love the type checking of tsx but I am not convinced that the material-ui library, great as it is explains how to utilise its styling with typescript.

I have followed the guide on here https://material-ui.com/guides/typescript/ to the letter and created a theme:

import { createMuiTheme } from "@material-ui/core/styles";

export default function theme() {
  return createMuiTheme({
  palette: {
    primary: {
      main: "#607D8B",
      light: "#CFD8DC",
      dark: "#455A64",
      contrastText: "#FFFFFF"
    },
    secondary: {
      main: "#7C4DFF",
      contrastText: "#212121"
    }
  }
})};

and I have created a style:

import { green, red } from "@material-ui/core/colors";
import { createStyles, withStyles } from "@material-ui/core/styles";
import { Theme } from '@material-ui/core';

const useStyles = (theme: Theme) => createStyles({
  root: {
    height: "100vh"
  },
  success: {
    backgroundColor: green[600]
  },
  error: {
    backgroundColor: red[800]
  },
  icon: {
    fontSize: 20
  },
  iconVariant: {
    opacity: 0.9,
    marginRight: theme.spacing(1)
  },
  message: {
    display: "flex",
    alignItems: "center"
  },
  image: {
    backgroundImage: "url(https://source.unsplash.com/8WFnEehJWso)",
    backgroundRepeat: "no-repeat",
    backgroundColor: theme.palette.primary.light,
    backgroundSize: "cover",
    backgroundPosition: "center"
  },
  paper: {
    height: "30vh",
    margin: theme.spacing(1.5, 3),
    display: "flex",
    flexDirection: "column",
    alignItems: "center"
  },
  mui_form: {
    width: "100%",
    marginTop: theme.spacing(1)
  },
  submit: {
    margin: theme.spacing(3, 0, 2)
  },
  card: {
    maxWidth: 600
  },
  media: {
    height: 500
  },
  circle: {
    display: "flex",
    "& > * + *": {
      marginLeft: theme.spacing(2)
    },
    align: "center"
  },
  menuButton: {
    marginRight: theme.spacing(2)
  },
  title: {
    flexGrow: 1,
    alignContent: "center"
  },
  pie: {
    height: 250,
    marginBottom: theme.spacing(2)
  },
  avatar: {
    margin: theme.spacing(1),
    backgroundColor: theme.palette.secondary.main
  },
  muiform: {
    width: "100%", // Fix IE 11 issue.
    marginTop: theme.spacing(1),
    "&:focus": {
      borderColor: "primary.dark"
    }
  },
  muisubmit: {
    margin: theme.spacing(3, 0, 2),
    padding: theme.spacing(3, 2),
    background: "primary.main",
    "&:hover": {
      backgroundColor: "primary.dark"
    }
  },
  login: {
    padding: "0 30px",
    height: 200,
    display: "flex",
    flexDirection: "column",
    justifyContent: "center"
  },
  loginImage: {
    backgroundImage: "url(https://source.unsplash.com/rCbdp8VCYhQ)",
    backgroundRepeat: "no-repeat",
    backgroundSize: "cover",
    backgroundPosition: "center",
    height: "100vh"
  },
  loginSurface: {
    height: "40vh",
    padding: "20px 10px",
    display: "flex",
    flexDirection: "column",
    alignItems: "center",
    background: "black"
  },
  table: {
    minWidth: 650
  }
});

export default withStyles(useStyles);

I have then tried to implement this on a component:

import DialogContent from "@material-ui/core/DialogContent";
import DialogContentText from "@material-ui/core/DialogContentText";
import DialogTitle from "@material-ui/core/DialogTitle";
import Slide from "@material-ui/core/Slide";
import Table from "@material-ui/core/Table";
import TableBody from "@material-ui/core/TableBody";
import TableCell from "@material-ui/core/TableCell";
import TableContainer from "@material-ui/core/TableContainer";
import TableHead from "@material-ui/core/TableHead";
import TableRow from "@material-ui/core/TableRow";
import Paper from "@material-ui/core/Paper";
import useStyles from "./useStyles";
import { TransitionProps } from "@material-ui/core/transitions";
import { useTheme } from '@material-ui/core/styles';
import { Theme } from '@material-ui/core';

const Transition = React.forwardRef<unknown, TransitionProps>(
  function Transition(props, ref) {
    return <Slide direction="up" ref={ref} {...props} />;
  }
);

export default function GuidanceDialogue(){
  const theme = useTheme<Theme>();
  const [open, setOpen] = React.useState(false);
  const classes = useStyles(theme);

The theme is accessed using useTheme and is passed down using the ThemeProvider in the root App.js.

The error I am getting is that:

const classes = useStyles(theme);

Argument of type 'Theme' is not assignable to parameter of type 'ComponentType; }>>'. Type 'Theme' is not assignable to type 'FunctionComponent; }>>'. Type 'Theme' provides no match for the signature '(props: PropsWithChildren; }>>, context?: any): ReactElement<...> | null'.ts(2345)

If I cast the type to be as follows:

const classes = useStyles<any>(theme);

So I can see if the type error is really the issue or there is other stuff going on then it mentions that the className property I am referring to e.g. classes.table, table doesn't exist.

I'm very confused by the whole thing, can some please help!

2

2 Answers

0
votes

Documentation of createStyles, makeStyles

By running the code below, I failed to reproduce your type error.

import { Theme, useTheme, makeStyles } from "@material-ui/core";

const useStyles = makeStyles((theme: Theme) => ({
  root: {}
}));

export default function App() {
  const theme = useTheme<Theme>();
  const classes = useStyles(theme);
  return (
    <div className="App">
      <h1 className={classes.root}>Theme</h1>
    </div>
  );
}

Try it online:

Edit kind-robinson-3j05i

2
votes

The solution was to write the following the styles file:

 const useStyles = makeStyles((theme: Theme) => createStyles({
  root: {