reactjs React + TypeScript使用Map而不是if/then进行联合类型收缩

4sup72z8  于 2023-01-25  发布在  React
关注(0)|答案(1)|浏览(125)

这是一个人为的例子,但是我想创建一个通用的React组件,它接受一些常见的prop,但是有一个prop的类型将根据传递给它的类型而变化。在本例中,data prop将是Type1Type2,并且我们将知道type,因为它将作为prop传递。

interface BaseProps {
    className: string
}

type SomethingProps = ({type: "type1"; data: Type1} & BaseProps) | ({type: "type2"; data: Type2} & BaseProps)

function Something(props: SomethingProps) {
    const Component = componentMap[props.type];
    return <Component data={props.data} className={props.className} /> // TS Error - 'Type1 | Type2' is not assignable to type 'Type1 & Type2'
}

const componentMap = {
    "type1": Type1Component, // FC<{data: Type1; className: string}>
    "type2": Type2Component // FC<{data: Type2; className: string}>
}

这可以很容易地解决,只需执行一个if/then检查,如下所示

function Something(props: SomethingProps) {
  if (props.type === "type1") {
    return <Type1Component data={props.data} className={props.className}/>
  }

  return <Type2Component data={props.data} className={props.className}/>

}

但是我想只使用map而不使用if/then语句。不使用类型转换有可能吗?

gev0vcfq

gev0vcfq1#

您是否考虑过创建一个新类型,将这两种常见类型组合起来,如下所示

type ComponentType = Type1Component | Type2Component;

const componentMap = {
    "type1": Type1Component,
    "type2": Type2Component
} as const;

function Something(props: SomethingProps) {
    const Component: ComponentType = componentMap[props.type];
    return <Component data={props.data} className={props.className} />
}

另一种方法是使用类型保护根据类型prop的值来缩小数据prop的类型。

interface BaseProps {
    className: string
}

interface Type1Props {
    type: "type1";
    data: Type1;
}
interface Type2Props {
    type: "type2";
    data: Type2;
}

type SomethingProps = Type1Props | Type2Props & BaseProps;

function isType1(props: SomethingProps): props is Type1Props {
    return props.type === "type1";
}

function Something(props: SomethingProps) {
    const Component = componentMap[props.type];
    if (isType1(props)) {
        return <Component data={props.data} className={props.className} />
    } else {
        return <Component data={props.data} className={props.className} />
    }
}

const componentMap = {
    "type1": Type1Component,
    "type2": Type2Component
} as const;

还可以使用typeof运算符使typeguard成为函数

function isType1(props: SomethingProps): props is Type1Props {
    return typeof props.data === "Type1";
}

相关问题