Объектные литералы для выбора конкретных компонентов react/typescript

#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 amp; { type: ItemType.NOTE; }
        amp; { 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 amp; { type: ItemType.NOTE; }
        amp; { type: ItemType.TASK; }' was reduced to 'never' because
        property 'type' has conflicting types in some constituents.
        ts(2322)
      */}
    </>
  );
}
 

Обновить:

Как вы устанавливаете ItemType.NOTE as const , когда значения возвращаются из API, а не жестко закодированы?

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


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

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

Комментарии:

1. Сработает ли что-то подобное NoteComponent(props: { type: ItemType }) ?

2. Я хочу использовать значения перечисления для выбора компонентов. Так <NoteComponent type={ItemType.TASK} /> и должно быть.

Ответ №1:

  1. getComp функция должна возвращать определенный компонент в соответствии с предоставленным типом (вместо объединения). Этого можно достичь с помощью перегрузок или дженериков.
  2. В объектном литерале { type: ItemType.NOTE } значение type расширено до ItemType , чтобы предотвратить использование этого as const утверждения.

 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} />
    </>
  );
}
 

Игровая площадка

Комментарии:

1. Как бы вы настроили ItemType.NOTE as const интерфейс?

2. например, когда вы динамически вводите реквизит из другого места

3. Обновленный исходный вопрос.