【问题标题】:How to type props for Material UI ListItem?如何为 Material UI ListItem 键入道具?
【发布时间】:2020-07-20 01:32:37
【问题描述】:

我正在尝试编写一个包装器组件,该组件将决定是让ListItem 呈现react-router-dom Link 还是button

// inside some component
let props

if ("uri" in navItem) {
  props = { component: Link, to: navItem.uri }           
} else {
  props = { button: true, onClick: navItem.onClick }   
}



return (
  <ListItem {...props}>
    ...some more code ...
  </ListItem
)

它在ListItem 上抱怨说没有超载匹配这个调用。我猜错误是因为没有输入props 变量。但是,我无法理解如何输入这个,这对于我的 TS 水平来说太复杂了。

我可以得到一些关于如何输入这些的指示吗?

编辑:

要添加更多信息,我只是想把它干掉:

export type NavItem = Omit<BaseNavItem, 'onClick'> | Omit<BaseNavItem, 'uri'>;

type BaseNavItem = {
  icon: React.ReactNode;
  label: string;
  uri: string;
  onClick: () => void;
};

// MyComponent.tsx
//   it will render Link or buttons depending
//   on whether uri or onClick was passed in the navItem
if ("uri" in navItem) {
  return (
    <li>
      <ListItem key={label} component={RouterLink} to={navItem.uri}>
        <ListItemIcon>{icon}</ListItemIcon>
        <ListItemText primary={label} />
      </ListItem>
    </li>
  )
} else {
  return (
    <ListItem key={label} button onClick={navItem.onClick}>
      <ListItemIcon>{icon}</ListItemIcon>
      <ListItemText primary={label} />
    </ListItem>
  )
}

【问题讨论】:

  • 你能给第一个例子更多的代码吗..
  • 添加了一些额外的代码,但不确定还有什么相关的

标签: reactjs typescript material-ui


【解决方案1】:

这是一个简单的解决方案:

import React from "react";
import { ListItem, ListItemIcon, ListItemText } from "@material-ui/core";
import { Link } from "react-router-dom";

interface INavItem {
  icon: React.ReactNode;
  label: string;
  // ? makes the prop optional
  // it can be undefined
  uri?: string;
  onClick?: () => void;
}

interface Props {
  navItem: INavItem;
}

function NavItem({ navItem }: Props) {
  const Inner = (
    <>
      <ListItemIcon>{navItem.icon}</ListItemIcon>
      <ListItemText primary={navItem.label} />
    </>
  );
  if (navItem.uri) {
    return (
      <ListItem component={Link} to={navItem.uri}>
        {Inner}
      </ListItem>
    );
  }

  return (
    <ListItem button onClick={navItem.onClick}>
      {Inner}
    </ListItem>
  );
}

export default NavItem;

至于根据component 属性定义props,它要复杂得多,在这种情况下没有必要。

查看文档:https://material-ui.com/guides/typescript/#usage-of-component-prop

例子:

import React, { ElementType } from "react";
import {
  ListItem,
  ListItemIcon,
  ListItemText,
  ListItemProps,
} from "@material-ui/core";
import { Link } from "react-router-dom";
import { People, Edit } from "@material-ui/icons";

interface INavItem {
  icon: React.ReactNode;
  label: string;
}

export type MyListItemProps<C extends ElementType> = ListItemProps<
  C,
  { component?: C }
> &
  INavItem;

function NavItem<C extends ElementType>({
  icon,
  label,
  ...props
}: MyListItemProps<C>) {
  return (
    <ListItem {...props}>
      <ListItemIcon>{icon}</ListItemIcon>
      <ListItemText primary={label} />
    </ListItem>
  );
}

const navItems = [
  { to: "/users", icon: People, label: "Users" },
  { icon: Edit, label: "Edit", onClick: () => {} },
];

// Usage
const Nav = () => {
  return navItems.map(({ to, icon, label, onClick }) => {
    if (to) {
      return <NavItem<Link> to={to} icon={icon} label={label} />;
    }
    return <NavItem icon={icon} label={label} button onClick={onClick} />;
  });
};

export default Nav;

const navItems = [
  { to: "/users", icon: People, label: "Users" },
  { icon: Edit, label: "Edit", onClick: () => {}, button: true },
];

// Usage
const Nav = () => {
  return navItems.map(({ to, ...props }) => {
    if (to) {
      return <NavItem<Link> to={to} {...props} />;
    }
    return <NavItem {...props} />;
  });
};

export default Nav;

【讨论】:

  • 它不会,但它会将您传递的任何额外道具转发给传递的Component
  • 我知道很抱歉我没有很好地阅读这个问题。您只是在寻找打字,我会检查并更新答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-01-14
  • 2019-10-13
  • 2018-04-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-08-19
相关资源
最近更新 更多