用于选择特定组件的对象文字反应/打字稿

时间:2021-05-20 10:24:55

标签: reactjs typescript react-typescript

是否可以使用带有枚举的对象字面量来返回 Typescript/React 中的不同组件?

如果没有,为什么这个模式不起作用?


enum ItemType {
  TASK,
  NOTE,
}

function NoteComponent(props: { type: ItemType.NOTE }) {
  return <div />;
}

function TaskComponent(props: { type: ItemType.TASK }) {
  return <div />;
}

function getComp(type: ItemType): typeof NoteComponent | typeof TaskComponent {
  return {
    [ItemType.NOTE]: NoteComponent,
    [ItemType.TASK]: TaskComponent,
  }[type];
}

const noteProps = { type: ItemType.NOTE };
const taskProps = { type: ItemType.TASK };

function App() {
  const Comp1 = getComp(noteProps.type);
  const Comp2 = getComp(taskProps.type);

  return (
    <>
      <Comp1 {...noteProps} />
      {/**
        Type '{ type: ItemType; }' is not assignable to type 'never'.
        The intersection 'IntrinsicAttributes & { type: ItemType.NOTE; }
        & { type: ItemType.TASK; }' was reduced to 'never' because
        property 'type' has conflicting types in some constituents.
        ts(2322)
      */}
      <Comp2 {...taskProps} />
      {/**
        Type '{ type: ItemType; }' is not assignable to type 'never'.
        The intersection 'IntrinsicAttributes & { type: ItemType.NOTE; }
        & { type: ItemType.TASK; }' was reduced to 'never' because
        property 'type' has conflicting types in some constituents.
        ts(2322)
      */}
    </>
  );
}

更新:

当值是从 API 返回而不是硬编码时,您如何设置 ItemType.NOTE as const

const apiResponse = [
    { type: ItemType.NOTE, ...noteSpecificProps },
    { type: ItemType.TASK ...taskSpecificProps },
];


apiResponse.map(item => {
    const Comp = getComp(noteProps.type);

    return <Comp {...item} />;
});

1 个答案:

答案 0 :(得分:2)

  1. getComp 函数应该根据提供的类型(而不是联合)返回特定的组件。这可以通过重载或泛型来实现。
  2. 在对象字面量 { type: ItemType.NOTE } 中,type 被扩展为 ItemType,以防止可以使用此 as const assertion

const componentMap = {
  [ItemType.NOTE]: NoteComponent,
  [ItemType.TASK]: TaskComponent,
}

function getComp<T extends ItemType>(type: T) {
  return componentMap[type];
}

const noteProps = { type: ItemType.NOTE } as const;
const taskProps = { type: ItemType.TASK } as const;

function App() {
  const Comp1 = getComp(noteProps.type);
  const Comp2 = getComp(taskProps.type);

  return (
    <>
      <Comp1 {...noteProps} />
      <Comp2 {...taskProps} />
    </>
  );
}

Playground

相关问题