Упор по умолчанию с обернутым стилизованным компонентом в Typescript - PullRequest
0 голосов
/ 15 января 2020

Я работаю над компонентом, который включает пару реквизитов по умолчанию, и я хочу передать их стилизованному компоненту. Вот где я сейчас нахожусь:

import React, { FC } from "react";
import styled from "styled-components";
// Icon SVG code
import Icons from "./icons";

const icons = ["add", "subtract"];

interface Props {
  className?: string;
  icon: typeof icons[number];
  size?: number;
}

const Wrapper = styled.div<Omit<Props, "icon">>(({ size }) => ({
  width: size,
  height: size
}));

const Icon: FC<Props> = ({ className, icon, size = 24 }) => (
  <Wrapper className={className} size={size}>
    <Icons icon={icon} />
  </Wrapper>
);

Для API компонента верхнего уровня, size должен иметь опору, так как он имеет значение по умолчанию (24). Тем не менее, size должен быть помечен как обязательный для компонента в стиле Wrapper, поскольку React гарантирует, что значение по умолчанию всегда применяется, если разработчик не предоставил его.

Интересно, кто-нибудь есть предложения по шаблонам проектирования для решения этой проблемы без необходимости перезаписывать варианты одного и того же интерфейса несколько раз. Я также использую последние версии всех зависимостей, включая TS, React и Styled Components.

Большое спасибо!

1 Ответ

0 голосов
/ 16 января 2020

Если я правильно вас понимаю, этот тип может помочь

type RequireKey<T, Key> = { [K in keyof Required<T>]: K extends Key ? NonNullable<T[K]> : T[K] }

Чтобы создать модифицированную версию Props, размер которой больше не может быть неопределенным, вы можете сделать

// The original Props that is Icon's external interface
interface Props {
  className?: string;
  icon: typeof icons[number];
  size?: number;
}

// Props with "size" made mandatory
type RequireSize = RequireKey<Props, "size">

// type RequireSize = {
//   className: string | undefined;
//   icon: string;
//   size: number; <- no longer optional!
// }

Если теперь вы используете RequireSize в Wrapper вместо Props, тогда тип "size" будет сужен до number вместо number | undefined

const Wrapper = styled.div<Omit<RequireSize, "icon">>(({ size }) => ({
  width: size,
  height: size
}));

// Use Props as before
const Icon: FC<Props> = ({ className, icon, size = 24 }) => (
  <Wrapper className={className} size={size}>
    <Icons icon={icon} />
  </Wrapper>
);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...