打字稿实现条件道具

时间:2021-01-26 16:40:29

标签: reactjs typescript types

我有以下组件,它可以包含图像或文本。因此,在 JSX 中,我检查是否有图像(因为这意味着不能有文本,反之亦然),然后显示图像或文本。

如何使用 TypeScript 类型定义此行为?

I BlockCtaDoubleData,始终可用,并且 EITHER BlockCtaDoubleImageData OR BlockCtaDoubleTextData

我尝试了以下操作,但 Typescript 不断为 props.textprops.image 抛出错误,但对于 props.headline 却没有。

怎么会?

interface BlockCtaDoubleData
{
    headline: string;
}

interface BlockCtaDoubleImageData extends BlockCtaDoubleData
{
    image: string;
    alt: string;
}

interface BlockCtaDoubleTextData extends BlockCtaDoubleData
{
    text: string;
}

export type BlockCtaDoubleProps = BlockCtaDoubleTextData | BlockCtaDoubleImageData;

export function BlockCtaDouble(props: BlockCtaDoubleProps)
{
    return (
        <div>
            {props.headline}
            {props.image ? (
                <img src={props.image} alt={props.alt}/>
            ) : (
                {props.text}
            )}
        </div>
    );
}

仅供参考:错误是说计数器类型中不存在相应的道具。

2 个答案:

答案 0 :(得分:1)

为了区分 import string if s[0] in string.digits: ... BlockCtaDoubleImageData,你需要一个类型保护。

BlockCtaDoubleTextData

类型保护是一个返回 import React from "react"; interface BlockCtaDoubleData { headline: string; } interface BlockCtaDoubleImageData extends BlockCtaDoubleData { image: string; alt: string; } interface BlockCtaDoubleTextData extends BlockCtaDoubleData { text: string; } export type BlockCtaDoubleProps = | BlockCtaDoubleTextData | BlockCtaDoubleImageData; const isBlockCtaDoubleImageData = ( a: BlockCtaDoubleProps ): a is BlockCtaDoubleImageData => a.hasOwnProperty("image"); const isBlockCtaDoubleTextData = ( a: BlockCtaDoubleProps ): a is BlockCtaDoubleTextData => a.hasOwnProperty("text"); export function BlockCtaDouble(props: BlockCtaDoubleProps) { return ( <div> {props.headline} {isBlockCtaDoubleImageData(props) ? ( <img src={props.image} alt={props.alt} /> ) : ( props.text )} </div> ); } 的函数。您需要以这种方式实现它:如果 x 是 Type 则返回 true,否则返回 false。具体条件由您决定。

编辑并回答评论中的问题

您无法通过您的方法实现它。你将不得不使用歧视联合。

x is Type

interface BlockCtaDoubleData {
  headline: string;
  type: "image" | "text";
}

interface BlockCtaDoubleImageData extends BlockCtaDoubleData {
  image: string;
  alt: string;
  type: "image";
}

interface BlockCtaDoubleTextData extends BlockCtaDoubleData {
  text: string;
  type: "text";
}

export type BlockCtaDoubleProps =
  | BlockCtaDoubleTextData
  | BlockCtaDoubleImageData;

export function BlockCtaDouble(props: BlockCtaDoubleProps) {
  return (
    <div>
      {props.headline}
      {props.type === "image" ? (
        <img src={props.image} alt={props.alt} />
      ) : (
        props.text
      )}
    </div>
  );
}

会抛出错误:

<BlockCtaDouble headline="as" text="xd" type="image" image="xd" />

答案 1 :(得分:1)

添加到现有答案中,您可以使用更简洁的行为 using in operator。您可以执行以下操作:

interface BlockCtaDoubleData
{
    headline: string;
}

interface BlockCtaDoubleImageData extends BlockCtaDoubleData
{
    image: string;
    alt: string;
}

interface BlockCtaDoubleTextData extends BlockCtaDoubleData
{
    text: string;
}

export type BlockCtaDoubleProps = BlockCtaDoubleTextData | BlockCtaDoubleImageData;

export function BlockCtaDouble(props: BlockCtaDoubleProps)
{
    return (
        <div>
            {props.headline}
            {("image" in props) ? (
                <img src={props.image} alt={props.alt}/>
            ) : (
                {props.text}
            )}
        </div>
    );
}

TS Playground to show the in behaviour