Как динамически расширить интерфейс или тип объекта в TypeScript?

Я пытаюсь использовать библиотеку PayPal Glamorous CSS-in-JS в стандартном проекте, который я создаю, который также использует TypeScript.

Glamorous позволяет добавлять реквизит к элементу примерно так:

const Section = glamorous.section([
  {
    ...styles
  },
  ({size}: any){
    if(size === 'big') return {fontSize: '48px';}
    else if(size === 'small') return {fontSize: '12px';}
  },
  ({alignment}: any){
    if(alignment === 'left') return {textAlign: 'left'}
    else if(alignment === 'right') return {textAlign: 'right'}
  }
]);

Так что вы можете использовать элемент в JSX следующим образом:

<Section size="big"></Section>

У меня есть несколько подобных вещей, которые я хотел бы добавить ко всем своим элементам, сгенерированным Glamorous. Итак, я создал вспомогательную функцию, которая выглядит следующим образом:

export const special = (glam: any, styles: object[]): GBPComp =>{
  return glam([styles as CSSStyleDeclaration[], specialProps]);
};

куда specialProps представляет функцию (аналогичную приведенной выше), которая добавляет различные реквизиты в мой массив объявлений стилей.

Я намерен использовать это так:

const Section = special(glamorous.section, [
  {
    ...styles
  }
]);

Затем я хочу, чтобы все реквизиты, предоставленные specialProps чтобы быть напечатанным для моего использования JSX. Итак, я попытался создать свой GBPComp типа как это:

export type GBPComp = React.StatelessComponent<CSSProperties&ExtraGlamorousProps&React.HTMLProps<HTMLElement>&{
  layout?: string,
  width?: string
}>;

Проблема возникает с тем фактом, что не все возвращаемые элементы обязательно будут иметь свойство React.HTMLProps<HTMLElement>, Они могут быть HTMLAnchorElement или же HTMLTableElement, так далее.

Как я могу быть в состоянии генерировать мой GBPComp введите динмически, так что он добавляет эти реквизиты (т.е. layout а также width) всем возвращаемым типам? Так что следующее будет правильно работать в TypeScript:

const Section = special(glamorous.section, [
  {
    ...styles
  }
]);

const Anchor = special(glamorous.a, [
  {
    ...styles
  }
]);

<a href="#" layout="someString">This is an Anchor</a>

<section layout="someString">This is a Section</section>

1 ответ

Если вы не хотите React.HTMLProps<HTMLElement> для каждого элемента вместо жесткого кодирования React.HTMLProps<HTMLElement>Вы могли бы использовать дженерики для вашего GBPComp вот так

export type GBPComp<ExtraProps> = React.StatelessComponent<React.CSSProperties & ExtraGlamorousProps & ExtraProps & { 
  layout: string,
  width: string
}>;

А также special() также принимает ExtraProps как дженерики и перейти к GBPComp вот так

export function special<ExtraProps>(glam: any, styles: object[], ...specialProps): GBPComp<ExtraProps> {
  return glam([styles as CSSStyleDeclaration[], ...specialProps]);
};

Теперь вы можете назначить React.HTMLProps<HTMLAnchorElement> реквизит для вашего Anchor

const Anchor = special<React.HTMLProps<HTMLAnchorElement>>(glamorous.a, [
  {
    ...styles
  }
]);
Другие вопросы по тегам