【问题标题】: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。

【问题讨论】:

    标签: reactjs typescript react-typescript discriminated-union typescript-types


    【解决方案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 顺便说一句,您的代码中有一些语法错误会阻止编译。如果它们只是问题中的拼写错误:没什么大不了的。但是,如果您需要这方面的帮助,它们会在答案中的游乐场链接中得到修复。
    • 我认为您没有正确理解我的问题。虽然您就在那里,一些语法错误和解构确实影响了类型(更新了问题中的两件事),但这不是我问题的要点。我的问题的要点是找到一种使用默认变体提供相同类型安全性的方法。
    猜你喜欢
    • 2022-01-13
    • 2017-09-03
    • 2021-05-17
    • 2017-06-20
    • 2016-10-26
    • 1970-01-01
    • 1970-01-01
    • 2016-03-31
    • 1970-01-01
    相关资源
    最近更新 更多