繁体   English   中英

React TypeScript 组件具有两个不同的 prop 接口

[英]React TypeScript component with two different prop interfaces

我想创建一个 React TypeScript 组件,其 props 是两个不同接口的联合。 但是,当我这样做时,我会收到警告:

TS2339: Property 'color' does not exist on type 'PropsWithChildren<Props>'

如何创建一个 React TypeScript 组件并结合两个不同的道具接口,同时能够解构这些道具? 谢谢!

示例组件.tsx:

import * as React from 'react';

interface SamplePropsOne {
  name: string;
}

interface SamplePropsTwo {
  color: string;
}

type Props = SamplePropsOne | SamplePropsTwo;

const SampleComponent: React.FC<Props> = ({ color, name }) => (
  color ? (
    <h1>{color}</h1>
  ) : (
    <h1>{name}</h1>
  )
);

export default SampleComponent;

在此处输入图像描述

在 TypeScript 让您从联合类型中读取namecolor之前,它需要一些证据证明您正在使用正确类型的道具( SamplePropsOneSamplePropsTwo )。 有一些标准方法可以提供它。

一种是通过引入一个属性来区分联合的分支,从而使联合成为标记联合。 这种类型检查就好了:

interface SamplePropsOne {
  type: 'one';
  name: string;
}

interface SamplePropsTwo {
  type: 'two';
  color: string;
}

type Props = SamplePropsOne | SamplePropsTwo;

const SampleComponent: React.FC<Props> = props => (
  props.type === 'one' ? (
    <h1>{props.name}</h1>
  ) : (
    <h1>{props.color}</h1>
  )
);

如果你把案例倒过来(就像我在写这篇文章时所做的那样),那么 TypeScript 会抱怨。

如果某个属性的存在足以区分类型,那么您可以使用in运算符:

interface SamplePropsOne {
  name: string;
}
interface SamplePropsTwo {
  color: string;
}
type Props = SamplePropsOne | SamplePropsTwo;

const SampleComponent: React.FC<Props> = props => (
  'color' in props ? (
    <h1>{props.color}</h1>
  ) : (
    <h1>{props.name}</h1>
  )
);

如果确定您拥有哪种类型的 object 需要更复杂的逻辑,您可以编写用户定义的类型保护 关键部分是返回类型中的“is”:

function isSampleOne(props: Props): props is SamplePropsOne {
  return 'name' in props;
}

const SampleComponent: React.FC<Props> = props => (
  isSampleOne(props) ? (
    <h1>{props.name}</h1>
  ) : (
    <h1>{props.color}</h1>
  )
);

还值得注意的是,由于结构类型的工作方式,您的示例中的props没有理由不能同时具有namecolor

const el = <SampleComponent name="roses" color="red" />;  // ok

如果不允许这样做很重要,您将需要使用一些稍微花哨的类型:

interface SamplePropsOne {
  name: string;
  color?: never;
}
interface SamplePropsTwo {
  color: string;
  name?: never;
}
type Props = SamplePropsOne | SamplePropsTwo;

ts-essentials 库有一个XOR泛型,可用于帮助构建这样的排他联合。

我认为您正在寻找的是交叉点类型

替换这一行:

type Props = SamplePropsOne | SamplePropsTwo;

用这条线:

type Props = SamplePropsOne & SamplePropsTwo;
  • 交集类型:将多个接口/类型合二为一

  • 联合类型:选择多种接口/类型之一

编辑

你想要的是不可能的(我认为)。 您可以做的是在转换props后在一行中解构每种类型:

const SampleComponent: React.FC<Props> = props => {
  const { name } = props as SamplePropsOne;
  const { color } = props as SamplePropsTwo;

  return color ? <h1>{color}</h1> : <h1>{name}</h1>;
};

我认为这会有所帮助

interface SamplePropsOne {
  name: string;
  color: never;
}

interface SamplePropsTwo {
  name: never;
  color: string;
}

type Props = SamplePropsOne | SamplePropsTwo;

const SampleComponent = ({ color, name }: Props) => {
  console.log(color ? color : name);
}

ts playground link: https://www.typescriptlang.org/play?#code/JYOwLgpgTgZghgYwgAgMpwLYAcA2EAKUA9lgM4DyIKA3gFDLIiYQBcypYUoA5gNz3IERHEShsqAN2j8AvrVqhIsRCnTY8hEqQAqAdyLI6DJhlaMIUqPwZCRY9px6z5YAJ5YUmssgC8aTLgExGSUKAA+-upBWnpE-LRCIByRgQDCRNhEVOC+yAAU1ILCogA0jMzIMmxepACUvgB8hgKJpMIQAHQi3Hm2osgA-EV2yOLMtbJAA

暂无
暂无

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

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