0
votes

in React I'm trying to rewrite js components to in tsx components. Therefore I'm simply converting PropTypes into TypeScript "types". Just getting started with TS, I'm producing plenty of errors "does not exist" (ts2339) and "is missing in type" (ts2741)

my old (js) file:

    import React from "react";
import PropTypes from "prop-types";

import {
  Dialog,
  DialogTitle,
  DialogContent,
  Typography,
  Tooltip,
  IconButton,
  List,
  ListItem,
  ListItemText,
} from "@material-ui/core";

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

import { Close as CloseIcon } from "@material-ui/icons";

const useStyles = makeStyles((theme) => ({
  closeButton: {
    position: "absolute",
    right: theme.spacing(1),
    top: theme.spacing(1),
  },
}));

function AboutDialog(props) {
  const classes = useStyles();
  const dialogProps = props.dialogProps;
  const user = props.user;
  const version = process.env.REACT_APP_VERSION;

  if (!user && !version) {
    return null;
  }

  return (
    <Dialog fullWidth maxWidth="xs" {...dialogProps}>
      <DialogTitle disableTypography>
        <Typography variant="h6">
          About {process.env.REACT_APP_TITLE}
        </Typography>

        <Tooltip title="Close">
          <IconButton
            className={classes.closeButton}
            onClick={dialogProps.onClose}
          >
            <CloseIcon />
          </IconButton>
        </Tooltip>
      </DialogTitle>

      <DialogContent>
        <List disablePadding>
          {version && (
            <ListItem>
              <ListItemText primary="Version" secondary={version} />
            </ListItem>
          )}

          {user && (
            <ListItem>
              <ListItemText primary="UID" secondary={user.uid} />
            </ListItem>
          )}
        </List>
      </DialogContent>
    </Dialog>
  );
}

AboutDialog.propTypes = {
  dialogProps: PropTypes.object.isRequired,
  user: PropTypes.object,
};

export default AboutDialog;

my new (tsx) file:

import React from "react";

import {
  Dialog,
  DialogTitle,
  DialogContent,
  Typography,
  Tooltip,
  IconButton,
  List,
  ListItem,
  ListItemText,
} from "@material-ui/core";

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

import { Close as CloseIcon } from "@material-ui/icons";

const useStyles = makeStyles((theme) => ({
  closeButton: {
    position: "absolute",
    right: theme.spacing(1),
    top: theme.spacing(1),
  },
}));

type AboutDialogProps = {
  dialogProps: object;
  user?: object;
};

const AboutDialog: React.FC<AboutDialogProps> = (props) => {
  const classes = useStyles();
  const dialogProps = props.dialogProps;
  const user = props.user;
  const version = process.env.REACT_APP_VERSION;

  if (!user && !version) {
    return null;
  }

  return (
    <Dialog fullWidth maxWidth="xs" {...dialogProps}>
      <DialogTitle disableTypography>
        <Typography variant="h6">
          About {process.env.REACT_APP_TITLE}
        </Typography>

        <Tooltip title="Close">
          <IconButton
            className={classes.closeButton}
            onClick={dialogProps.onClose}
          >
            <CloseIcon />
          </IconButton>
        </Tooltip>
      </DialogTitle>

      <DialogContent>
        <List disablePadding>
          {version && (
            <ListItem>
              <ListItemText primary="Version" secondary={version} />
            </ListItem>
          )}

          {user && (
            <ListItem>
              <ListItemText primary="UID" secondary={user.uid} />
            </ListItem>
          )}
        </List>
      </DialogContent>
    </Dialog>
  );
};

export default AboutDialog;

Error 1: Property 'open' is missing in type '{ children: Element[]; fullWidth: true; maxWidth: "xs"; }' but required in type 'DialogProps'.ts(2741) Dialog.d.ts(88, 3): 'open' is declared here.

Error 2: Property 'onClose' does not exist on type 'object'.ts(2339)

Error 3: Property 'uid' does not exist on type 'object'.ts(2339)

Trying to fix stuff in the other components just produces more mistakes. What am I conceptually failing to understand here? // How would you go about converting/refactoring it?

UPDATE after fix from the first two comments (Mar 21st): import React from "react";

import {
  Dialog,
  DialogTitle,
  DialogContent,
  Typography,
  Tooltip,
  IconButton,
  List,
  ListItem,
  ListItemText,
  DialogProps,
} from "@material-ui/core";

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

import { Close as CloseIcon } from "@material-ui/icons";

const useStyles = makeStyles((theme) => ({
  closeButton: {
    position: "absolute",
    right: theme.spacing(1),
    top: theme.spacing(1),
  },
}));

interface User {
  uid: string;
  email: string;
  emailVerified: string;
  password: string;
  displayName: string;
  photoURL: string;
  disabled: string;
};

interface AboutDialogProps {
  dialogProps?: DialogProps;
  user?: User;
  onClose: () => void;
};

const AboutDialog = (props: AboutDialogProps) => {
  const classes = useStyles();
  const dialogProps = props.dialogProps;
  const user = props.user;
  const version = process.env.REACT_APP_VERSION;

  if (!user && !version) {
    return null;
  }

  return (
    <Dialog fullWidth maxWidth="xs" {...dialogProps}>
      <DialogTitle disableTypography>
        <Typography variant="h6">
          About {process.env.REACT_APP_TITLE}
        </Typography>

        <Tooltip title="Close">
          <IconButton
            className={classes.closeButton}
            onClick={dialogProps.onClose}
          >
            <CloseIcon />
          </IconButton>
        </Tooltip>
      </DialogTitle>

      <DialogContent>
        <List disablePadding>
          {version && (
            <ListItem>
              <ListItemText primary="Version" secondary={version} />
            </ListItem>
          )}

          {user && (
            <ListItem>
              <ListItemText primary="UID" secondary={user.uid} />
            </ListItem>
          )}
        </List>
      </DialogContent>
    </Dialog>
  );
};

export default AboutDialog;

This throws new errors on IconButton: " No overload matches this call. Overload 1 of 3, '(props: { href: string; } & { color?: Color | undefined; disableFocusRipple?: boolean | undefined; edge?: false | "end" | "start" | undefined; size?: "medium" | "small" | undefined; } & { ...; } & CommonProps<...> & Pick<...>): Element', gave the following error. Type '((event: {}, reason: "backdropClick" | "escapeKeyDown") => void) | undefined' is not assignable to type 'MouseEventHandler | undefined'. Type '(event: {}, reason: "backdropClick" | "escapeKeyDown") => void' is not assignable to type 'MouseEventHandler'. Overload 2 of 3, '(props: { component: ElementType; } & { color?: Color | undefined; disableFocusRipple?: boolean | undefined; edge?: false | "end" | "start" | undefined; size?: "medium" | "small" | undefined; } & { ...; } & CommonProps<...> & Pick<...>): Element', gave the following error. Property 'component' is missing in type '{ children: Element; className: string; onClick: ((event: {}, reason: "backdropClick" | "escapeKeyDown") => void) | undefined; }' but required in type '{ component: ElementType; }'. Overload 3 of 3, '(props: DefaultComponentProps<ExtendButtonBaseTypeMap<IconButtonTypeMap<{}, "button">>>): Element', gave the following error. Type '((event: {}, reason: "backdropClick" | "escapeKeyDown") => void) | undefined' is not assignable to type 'MouseEventHandler | undefined'. Type '(event: {}, reason: "backdropClick" | "escapeKeyDown") => void' is not assignable to type 'MouseEventHandler'.ts(2769) index.d.ts(1449, 9): The expected type comes from property 'onClick' which is declared here on type 'IntrinsicAttributes & { href: string; } & { color?: Color | undefined; disableFocusRipple?: boolean | undefined; edge?: false | "end" | "start" | undefined; size?: "medium" | ... 1 more ... | undefined; } & { ...; } & CommonProps<...> & Pick<...>' OverridableComponent.d.ts(17, 7): 'component' is declared here. index.d.ts(1449, 9): The expected type comes from property 'onClick' which is declared here on type 'IntrinsicAttributes & { color?: Color | undefined; disableFocusRipple?: boolean | undefined; edge?: false | "end" | "start" | undefined; size?: "medium" | "small" | undefined; } & { ...; } & CommonProps<...> & Pick<...>' "

... and on Dialog: " Type '{ children: Element[]; 'aria-describedby'?: string | undefined; 'aria-labelledby'?: string | undefined; disableBackdropClick?: boolean | undefined; disableEscapeKeyDown?: boolean | undefined; ... 285 more ...; classes?: Partial<...> | undefined; }' is not assignable to type 'DialogProps'. Types of property 'open' are incompatible. Type 'boolean | undefined' is not assignable to type 'boolean'. Type 'undefined' is not assignable to type 'boolean'.ts(2322) "

2
also, the npm packages available for transforming js to typescript seem to have very few downloads (e.g. react-proptypes-to-typescript or react-js-to-ts). i guess plenty of people must have similar problems converting js to ts, can you recomnmend anything than automizes it?dennyalem

2 Answers

0
votes

You want to be a bit more specific than "object" when you define your types. Something like this should work

type User = {
    uid: string;
    //add all the property of your user
};

type AboutDialogProps = {
    dialogProps: DialogProps; //DialogProps is imported from @material-ui/core
    user?: User;
};

0
votes

Typescript is strongly types language. Let's focus on Errors:

  1. open is untype.
  2. onClose is untype.
  3. uid is untype.

It's object so i suggest to create interface IOpen:

interface IOpen {
 children: Array<Element>
 fullWidth: boolean;
 maxWidth: string
}

onClose - there is probably need type:

onClose: () => void

uid - there is probably need type - i seen that uid is string inside user object. So there is possiblity to add another interface:

interface IUser {
 (...)
 uid:string
 (...)
}

In your case you type user like object and it's true - but the ts compiler require more specific informations.