在具有默认值的反应道具中使用区分联合

Posted

技术标签:

【中文标题】在具有默认值的反应道具中使用区分联合【英文标题】:Using discriminating unions in react props with a default 【发布时间】:2022-01-20 22:42:40 【问题描述】:

我有一个包含 3 个变体的反应组件。我的道具是这样输入的:

enum VariantType 
  VARIANT_1 = "variant_1",
  VARIANT_2 = "variant_2",
  VARIANT_3 = "variant_3",


type BaseProps = 
  a: string;


type Variant1Props = BaseProps & 
  variant: VariantType.VARIANT_1;
  b: never;


type Variant2Props = BaseProps & 
  variant: VariantType.VARIANT_2;
  b: number;


type Variant3Props = BaseProps & 
  variant: VariantType.VARIANT_3;
  b: boolean;


export const FancyComponent: FunctionComponent<Variant1Props | Variant2Props | Variant3Props> = (props) => 
  const someNumber = props.variant === VariantType.VARIANT_2 ? props.b : 123; 
   ...

在 someNumber 的分配中,TS 知道 b 是定义的,因为我检查了变体。当使用组件时,当b 存在时,TS 会抱怨VARIANT_1,当b 不存在/不是数字时,它会抱怨VARIANT_2VARIANT_3 相同)。

我现在正在寻找的是一种在使用组件时使 variant 选项可选的方法,它应该默认为 VARIANT_1 并且您可以将其设置为 VARIANT_2VARIANT_3 而不会丢失任何我现在拥有的类型安全。

我尝试过使用泛型等的东西,但无法正常工作。

我正在使用 Typescript 4.5。

【问题讨论】:

【参考方案1】:

一旦你解构了你的props,再区分它们就太晚了,因为它们不再相互关联。相反,您需要区分对象本身,然后进行解构。您可以通过以下几种方式做到这一点:

TS Playground

type AllVariants = Variant1Props | Variant2Props | Variant3Props;

// Example 1
export const FancyComponent1 = (props: AllVariants): ReactElement => 
  const someNumber = props.variant === VariantType.VARIANT_2 ? props.b : 123; // number
  return <div></div>;


// Example 2: Using conditional
export const FancyComponent2 = (props: AllVariants): ReactElement => 
  if (props.variant === VariantType.VARIANT_2) 
    const 
      a, // string
      b, // number
      variant, // VariantType.VARIANT_2
     = props;
  
  return <div></div>;



// Example 3: Extracting conditional in #2 to predicate:
// https://www.typescriptlang.org/docs/handbook/2/narrowing.html#using-type-predicates

function isVariant2 (props: AllVariants): props is Variant2Props 
  return props.variant === VariantType.VARIANT_2;


export const FancyComponent3 = (props: AllVariants): ReactElement => 
  if (isVariant2(props)) 
    const 
      a, // string
      b, // number
      variant, // VariantType.VARIANT_2
     = props;
  
  return <div></div>;

【讨论】:

@PieterVanderHaegen 顺便说一句,您的代码中有一些语法错误会阻止编译。如果它们只是问题中的拼写错误:没什么大不了的。但是,如果您需要这方面的帮助,它们会在答案中的游乐场链接中得到修复。 我认为您没有正确理解我的问题。虽然您就在那里,一些语法错误和解构确实影响了类型(更新了问题中的两件事),但这不是我问题的要点。我的问题的要点是找到一种使用默认变体提供相同类型安全性的方法。

以上是关于在具有默认值的反应道具中使用区分联合的主要内容,如果未能解决你的问题,请参考以下文章

反应式默认道具值

空F#区分联合案例的C#类型

groovy中具有默认值的命名参数

使用 Dapper 插入具有默认值的表

Vue:为数组属性设置默认值的最佳方法?

React/Redux 中具有默认值的文本输入