繁体   English   中英

使用 TypeScript 和 React 联合类型

[英]Union types with TypeScript and React

我想要一个组件根据给定的特定属性的值接受不同的 props。 类似于以下内容。

const Button: React.FC<TButton> = ({ href, children, ...rest }) => {
  if (href) {
    return <a href={href} {...rest}>{children}</a>
  }

  return <button {...rest}>{children}</button>
}

type TButton = { href: string & IAnchor } | { href: undefined & IButton }

interface IAnchor extends React.AnchorHTMLAttributes<HTMLAnchorElement> {}
interface IButton extends React.ButtonHTMLAttributes<HTMLButtonElement> {}

问题是,无法弄清楚如何正确地经历这个。 我的意思是,似乎条件没有被正确解析或解释。

如果您想仔细查看该问题,请参阅此 StackBlitz

似乎您基本上尝试使用歧视 union 但似乎它不适用于...rest 所以为了让它工作

  1. 为两个接口添加额外的属性,比如将用作判别type

     interface IAnchor extends React.DetailedHTMLProps<React.AnchorHTMLAttributes<HTMLAnchorElement>, HTMLAnchorElement> { type: 'anchor' href: string } interface IButton extends React.ButtonHTMLAttributes<HTMLButtonElement> { type: 'button' }
  2. 接受porps ,然后在条件分支中销毁它们

    const Button: React.FC<TButton> = (props): JSX.Element => { if (props.type === 'anchor') { const { type, href, children, ...rest } = props; return ( <a href={href} {...rest}> {children} </a> ) } const { type, children, ...rest } = props; return <button {...rest}>{children}</button> }

查看 工作示例

我查看了您的 StackBlitz,并能够使用ts-toolbelt库来解决这个问题:

首先,让我们定义两个不同的可能的 prop 类型(所有锚 props 和所有按钮 props),将它们组合为一个严格的联合并使用类型保护让我们的 React 组件知道我们何时使用哪组 props:

import { Union } from 'ts-toolbelt'

type TButton = Union.Strict<IAnchor | IButton>

interface IAnchor extends React.AnchorHTMLAttributes<HTMLAnchorElement> {}

interface IButton extends React.ButtonHTMLAttributes<HTMLButtonElement> {}

const isAnchor = (props: TButton): props is IAnchor => {
  return props.href !== undefined;
}
const isButton = (props: TButton): props is IButton => {
  return props.type !== undefined
}

现在,让我们编写可以是按钮或锚点的自定义组件:

const Button: React.FC<TButton> = ({ children, ...props }): JSX.Element => {
  if (isAnchor(props)) {
    return (
      <a href={props.href} {...props}>
        {children}
      </a>
    )
  } else if (isButton(props)) {
    return <button {...props}>{children}</button>
  }
}

您可以在此 StackBlitz 中查看它的工作情况

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM