Распространение реквизитов расширенного типа в интерфейс Typescript

#typescript #typescript-typings #typescript-generics

#машинописный текст #typescript-типизации #typescript-дженерики

Вопрос:

У меня есть следующие интерфейсы:

 interface ButtonProps {
  name: string;
}

interface IconButtonProps {
  name: string;
  icon: string;
} 

Я пытаюсь создать тип для следующего компонента:

 <MyGenericComponent component={button} name="button">...
<MyGenericComponent component={iconButton} name="icon-button" icon="icon">... 

Идея в том, что я не могу ввести интерфейс, который будет представлять MyGenericComponentProps , чтобы он мог принимать компонент react в component prop, если все остальные реквизиты, предоставленные ему, являются теми, которые принимает данный компонент!

Что — то вроде этого:

 interface MyGenericComponentProps<T> extends T {
  component: React.FC<T>;
} 

…где T выше может быть ButtonProps или IconButtonProps . Я знаю, что не могу расширить T , потому что он статически неизвестен, но тогда как мне убедиться, что остальные данные реквизита относятся к одному ButtonProps или IconButtonProps ?

ОБНОВЛЕНИЕ: вот определение компонента после ответа:

 import React from 'react';
import { ButtonProps, IconButtonProps } from '@material-ui/core';

type MyGenericComponentProps<T> = {
    component: React.FC<T>;
} amp; {
    [key in keyof T]: T[key];
};

const MyGenericComponent = <T extends object>({ component, ...props }: MyGenericComponentProps<T>) => {
    // ... more code here
    const Component = component;
    return <Component {...props} />;
};

export default MyGenericComponent; 

Ответ №1:

Если не имеет смысла, какой объект TS будет использоваться (тип или интерфейс), вы можете ввести его как тип вместо интерфейса:

 type MyGenericComponentProps<T> = {
  component: React.FC<T>;
} amp; {
  [key in keyof T]: T[key];
}
 

[ОБНОВЛЕНИЕ]:

Вам нужно изменить и даже упростить некоторые фрагменты:

 type MyGenericComponentProps<T> = {
  component: React.FC<T>;
  props: T; 
}

const MyGenericComponent = <T extends object>({component: Component, props}: MyGenericComponentProps<T>) => {
  // ... more code here
  return <Component {...props}/>;
};
 

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

1. Спасибо. Проблема в том, что при попытке реализовать MyGenericComponent его после я получаю следующую ошибку: введите ‘Pick<MyGenericComponentProps<T>, Исключите<keyof T, «component»>>’ не может быть присвоен типу ‘IntrinsicAttributes amp; T amp; { дочерние элементы?: ReactNode; }’. Тип ‘Выбрать<MyGenericComponentProps<T>, исключить<keyof T, «компонент»>>’ не может быть присвоен типу ‘T’. ‘Выбрать<MyGenericComponentProps<T>, исключить<keyof T, «component»>>’ можно назначить ограничению типа ‘T’, но ‘T’ может быть создан с другим подтипом ограничения ‘MyGenericComponentProps’.ts(2322)

2. К вашему сведению, то, что я пытаюсь сделать внутри MyGenericComponent , заключается let Component = component в том <Component {...props} /> , что я получаю ошибку выше.

3. Пожалуйста, покажите, как вы определяете MyGenericComponent .

4. Я только что обновил вопрос, чтобы поделиться полным определением. Заранее спасибо.

5. Спасибо, но таким образом у меня нет props как части самих свойств интерфейса. Я не хочу передавать реквизит в props объекте, а напрямую.

Ответ №2:

 interface ButtonProps {
  name: string;
}

interface IconButtonProps extends ButtonProps{
  icon?: string;
}
 

и

 interface MyGenericComponentProps<IconButtonProps>{
  component: React.FC<IconButtonProps>;
}
 

не знаю о react, но с помощью typescript вы можете расширять интерфейсы и объявлять необязательные свойства. Тогда это будет принимать ButtonProps и IconButtonProps