1

I am new to typeScript and I am using this materialUI premium theme OnePirate and I am using the Footer component and it is working perfectly fine in the js but when I am moving the same Footer component to my project and rename the component to .tsx It throws errors saying "No Overload matches this call" Here is the code:

import React from "react";
import { makeStyles } from "@material-ui/core/styles";
import Grid from "@material-ui/core/Grid";
import Link from "@material-ui/core/Link";
import Container from "@material-ui/core/Container";
import Typography from "./materialUi/Typography";
import TextField from "./materialUi/TextField";
import fbicon from "./static/themes/onepirate/appFooterFacebook.png";
import twicon from "./static/themes/onepirate/appFooterTwitter.png";

const useStyles = makeStyles((theme) => ({
  root: {
    display: "flex",
    backgroundColor: theme.palette.secondary.light,
  },
  container: {
    marginTop: theme.spacing(8),
    marginBottom: theme.spacing(8),
    display: "flex",
  },
  iconsWrapper: {
    height: 120,
  },
  icons: {
    display: "flex",
  },
  icon: {
    width: 48,
    height: 48,
    display: "flex",
    justifyContent: "center",
    alignItems: "center",
    backgroundColor: theme.palette.warning.main,
    marginRight: theme.spacing(1),
    "&:hover": {
      backgroundColor: theme.palette.warning.dark,
    },
  },
  list: {
    margin: 0,
    listStyle: "none",
    paddingLeft: 0,
  },
  listItem: {
    paddingTop: theme.spacing(0.5),
    paddingBottom: theme.spacing(0.5),
  },
  language: {
    marginTop: theme.spacing(1),
    width: 150,
  },
}));

const LANGUAGES = [
  {
    code: "en-US",
    name: "English",
  },
  {
    code: "fr-FR",
    name: "Français",
  },
];

function Footer() {
  const classes = useStyles();

  return (
    <Typography component="footer" className={classes.root}>
      <Container className={classes.container}>
        <Grid container spacing={5}>
          <Grid item xs={6} sm={4} md={3}>
            <Grid
              container
              direction="column"
              justify="flex-end"
              className={classes.iconsWrapper}
              spacing={2}
            >
              <Grid item className={classes.icons}>
                <a href="https://material-ui.com/" className={classes.icon}>
                  <img src={fbicon} alt="Facebook" />
                </a>
                <a
                  href="https://twitter.com/MaterialUI"
                  className={classes.icon}
                >
                  <img src={twicon} alt="Twitter" />
                </a>
              </Grid>
              <Grid item>© 2019 Onepirate</Grid>
            </Grid>
          </Grid>
          <Grid item xs={6} sm={4} md={2}>
            <Typography variant="h6" marked="left" gutterBottom>
              Legal
            </Typography>
            <ul className={classes.list}>
              <li className={classes.listItem}>
                <Link href="/premium-themes/onepirate/terms/">Terms</Link>
              </li>
              <li className={classes.listItem}>
                <Link href="/premium-themes/onepirate/privacy/">Privacy</Link>
              </li>
            </ul>
          </Grid>
          <Grid item xs={6} sm={8} md={4}>
            <Typography variant="h6" marked="left" gutterBottom>
              Language
            </Typography>
            <TextField
              select
              SelectProps={{
                native: true,
              }}
              className={classes.language}
            >
              {LANGUAGES.map((language) => (
                <option value={language.code} key={language.code}>
                  {language.name}
                </option>
              ))}
            </TextField>
          </Grid>
          <Grid item>
            <Typography variant="caption">
              {"Icons made by "}
              <Link
                href="https://www.freepik.com"
                rel="nofollow"
                title="Freepik"
              >
                Freepik
              </Link>
              {" from "}
              <Link
                href="https://www.flaticon.com"
                rel="nofollow"
                title="Flaticon"
              >
                www.flaticon.com
              </Link>
              {" is licensed by "}
              <Link
                href="https://creativecommons.org/licenses/by/3.0/"
                title="Creative Commons BY 3.0"
                target="_blank"
                rel="noopener noreferrer"
              >
                CC 3.0 BY
              </Link>
            </Typography>
          </Grid>
        </Grid>
      </Container>
    </Typography>
  );
}
export default Footer;

This is the Typography code if I don't import from material UI

import React from "react";
import PropTypes from "prop-types";
import { withStyles } from "@material-ui/core/styles";
import { capitalize } from "@material-ui/core/utils";
import MuiTypography from "@material-ui/core/Typography";

const styles = (theme) => ({
  markedH2Center: {
    height: 4,
    width: 73,
    display: "block",
    margin: `${theme.spacing(1)}px auto 0`,
    backgroundColor: theme.palette.secondary.main,
  },
  markedH3Center: {
    height: 4,
    width: 55,
    display: "block",
    margin: `${theme.spacing(1)}px auto 0`,
    backgroundColor: theme.palette.secondary.main,
  },
  markedH4Center: {
    height: 4,
    width: 55,
    display: "block",
    margin: `${theme.spacing(1)}px auto 0`,
    backgroundColor: theme.palette.secondary.main,
  },
  markedH6Left: {
    height: 2,
    width: 28,
    display: "block",
    marginTop: theme.spacing(0.5),
    background: "currentColor",
  },
});

const variantMapping = {
  h1: "h1",
  h2: "h1",
  h3: "h1",
  h4: "h1",
  h5: "h3",
  h6: "h2",
  subtitle1: "h3",
};

function Typography(props) {
  const { children, classes, marked = false, variant, ...other } = props;

  return (
    <MuiTypography variantMapping={variantMapping} variant={variant} {...other}>
      {children}
      {marked ? (
        <span
          className={
            classes[`marked${capitalize(variant) + capitalize(marked)}`]
          }
        />
      ) : null}
    </MuiTypography>
  );
}

Typography.propTypes = {
  children: PropTypes.node,
  classes: PropTypes.object.isRequired,
  marked: PropTypes.oneOf([false, "center", "left"]),
  variant: PropTypes.string,
};

export default withStyles(styles)(Typography);

This is the error now: This is the error if i use the typography file

2
  • The error is pretty self-explanatory. There is no marked property in Typography component. Commented Jun 30, 2020 at 15:17
  • @MezbaulHaque see the edited version. What am I missing? Commented Jun 30, 2020 at 15:27

1 Answer 1

2

TL;DR: I've open sourced my implementation of onepirate in Typescript so you can just use that: https://github.com/rothbart/onepirate-typescript

This is a great question. Onepirate is a great resource but as you've noticed it isn't really built in a way that's Typescript friendly.

Your problem here is that the Typography implementation in onepirate isn't doing a great job of specifying which properties it expects, and is relying on the fact that vanilla JS will mostly just pass everything through to the underlying MuiTypography component.

Here's a much cleaner Typography implementation that preserves the underline effect in onepirate works with Typescript:

import React from "react";
import PropTypes, { InferProps } from "prop-types";
import {
  withStyles,
  WithStyles,
  createStyles,
  Theme,
} from "@material-ui/core/styles";
import MuiTypography, { TypographyProps } from "@material-ui/core/Typography";

const styles = (theme: Theme) =>
  createStyles({
    markedH2Center: {
      height: 4,
      width: 73,
      display: "block",
      margin: `${theme.spacing(1)}px auto 0`,
      backgroundColor: theme.palette.secondary.main,
    },
    markedH3Center: {
      height: 4,
      width: 55,
      display: "block",
      margin: `${theme.spacing(1)}px auto 0`,
      backgroundColor: theme.palette.secondary.main,
    },
    markedH4Center: {
      height: 4,
      width: 55,
      display: "block",
      margin: `${theme.spacing(1)}px auto 0`,
      backgroundColor: theme.palette.secondary.main,
    },
    markedH6Left: {
      height: 2,
      width: 28,
      display: "block",
      marginTop: theme.spacing(0.5),
      background: "currentColor",
    },
  });

function getMarkedClassName(variant: string) {
  switch (variant) {
    case "h2":
      return "markedH2Center";
    case "h3":
      return "markedH3Center";
    case "h4":
      return "markedH4Center";
  }
  return "markedH6Left";
}

const variantMapping = {
  h1: "h1",
  h2: "h1",
  h3: "h1",
  h4: "h1",
  h5: "h3",
  h6: "h2",
  subtitle1: "h3",
};

function Typography<C extends React.ElementType>(
  props: TypographyProps<C, { component?: C }> &
    WithStyles<typeof styles> &
    InferProps<typeof Typography.propTypes>
) {
  const { children, variant, classes, marked, ...other } = props;

  return (
    <MuiTypography variantMapping={variantMapping} variant={variant} {...other}>
      {children}
      {marked ? (
        <span className={classes[getMarkedClassName(variant as string)]} />
      ) : null}
    </MuiTypography>
  );
}

Typography.propTypes = {
  marked: PropTypes.oneOf([false, "center", "left"]),
};

Typography.defaultProps = {
  marked: false,
};

export default withStyles(styles)(Typography);

Just a heads up that will run into this same problem with other onepirate components as well (I just finished re-implementing most of them in Typescript so I could use them in my own web app). If you're trying to reverse engineer how I did this I'd pay particular attention to how I took advantage of MuiTypography props and then just added the one new property I needed (marked).

TypographyProps<C, { component?: C }> &
    WithStyles<typeof styles> &
    InferProps<typeof Typography.propTypes>

I'd also highly recommend reading over https://material-ui.com/guides/typescript/ if you haven't already, it's a super helpful guide for understanding some of the Typescript gotchas in Material-UI.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.