#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:
getComp
функция должна возвращать определенный компонент в соответствии с предоставленным типом (вместо объединения). Этого можно достичь с помощью перегрузок или дженериков.- В объектном литерале
{ 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. Обновленный исходный вопрос.