Требуемый проп для стилизованного компонента, несмотря на то, что он указан с помощью attr

Вопрос или проблема

Я создал базовый компонент иконки, который расширяет SVG из react-inlinesvg, используя styled-components, чтобы позволить кастомизировать стили. Кроме того, вызов attr указывает свойство src для компонента SVG, поскольку разные файлы SVG будут иметь разные реализации стилей, поэтому каждый из них является собственным компонентом. Вот соответствующий код:

import SVG from 'react-inlinesvg';
import { CSSProperties as _CSSProperties } from "react";
import styled, { Interpolation } from "styled-components";

// Удаляем undefined из CSSProperties, так как все эти константы гарантированно
// существуют.
export type RequiredCSSProperties = Required<_CSSProperties>;

// Добавляем проп, который позволяет добавить пользовательский CSS к экземпляру стилизованного компонента без
// создания нового стилизованного компонента.
export type WithCSSProp<T={}> = T & { $css?: Interpolation<Omit<T, "$css">> };

export type MenuIconStyleAttributes = {
    $color?: RequiredCSSProperties['stroke'] | null;
    $width?: RequiredCSSProperties['width'];
    $height?: RequiredCSSProperties['height'];
};

export default styled(SVG).attrs<WithCSSProp<MenuIconStyleAttributes>>(
    (props) => ({
        src: '/icons/menu.svg',
        $color: props.$color ?? null,
        $width: props.$width ?? '24px',
        $height: props.$height ?? 'auto',
        $css: props.$css ?? null
    })
)`
    width: ${({$width}) => $width};
    height: ${({$height}) => $height};

    > path {
        stroke: ${({$color, theme}) => $color ?? theme.textColor};
    }

    ${({$css}) => $css}
`;

Моя проблема заключается в том, что, когда я использую этот компонент, свойство src рассматривается как обязательное, хотя оно указано со статическим значением. Точная ошибка:

Нет совпадений для этого вызова.
  Перегрузка 1 из 2, '(props: PolymorphicComponentProps<"web", FastOmit<Substitute<Substitute<{ string?: string | number | undefined; stroke?: string | undefined; clipPath?: string | undefined; color?: string | undefined; cursor?: string | number | undefined; ... 481 более ...; uniquifyIDs?: boolean | undefined; }, { ...; }>, WithCSSProp<...>>, never>, void, void, {}, {}>): Element', вызвала следующую ошибку.
    Свойство 'src' отсутствует в типе '{}' но обязательно в типе 'FastOmit<Substitute<FastOmit<Substitute<Substitute<{ string?: string | number | undefined; stroke?: string | undefined; clipPath?: string | undefined; color?: string | undefined; cursor?: string | number | undefined; direction?: string | ... 1 более ... | undefined; ... 480 более ...; uniquifyIDs?: boolean | undefined...'.
  Перегрузка 2 из 2, '(props: FastOmit<Substitute<Substitute<{ string?: string | number | undefined; stroke?: string | undefined; clipPath?: string | undefined; color?: string | undefined; cursor?: string | number | undefined; direction?: string | ... 1 более ... | undefined; ... 480 более ...; uniquifyIDs?: boolean | undefined; }, { ...; }>, WithCSSProp<...>>, never>): ReactNode', вызвала следующую ошибку.
    Свойство 'src' отсутствует в типе '{}' но обязательно в типе 'FastOmit<Substitute<Substitute<{ string?: string | number | undefined; stroke?: string | undefined; clipPath?: string | undefined; color?: string | undefined; cursor?: string | number | undefined; direction?: string | ... 1 более ... | undefined; ... 480 более ...; uniquifyIDs?: boolean | undefined; }, { ...; }>, With...'.

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

Ответ или решение

Проблема с обязательным свойством src в компоненте, использующем styled-components

Ваша проблема с тем, что свойство src компонента SVG из библиотеки react-inlinesvg воспринимается как обязательное, хотя значение задается статически, действительно может вызывать затруднения. Расберем эту ситуацию более подробно.

Понимание ошибки

Ошибка, с которой вы столкнулись, указывает на то, что TypeScript требует наличие свойства src для вашего компонента, несмотря на то, что вы задали его статически через attrs. Это происходит потому, что типы, связанные с SVG, не учитывают статическую привязку, делая src обязательным свойством.

Как это исправить

Варианты решения проблемы зависят от вашего подхода к типизации. Рассмотрим несколько стратегий:

  1. Создание обертки: Один из способов избавиться от обязательного свойства src — это создать новый компонент (обертку) вокруг компонента SVG, который не будет требовать src. Вы можете создать компонент, который добавляет attrs и передает необходимые пропсы без необходимости явно указывать src:

    import SVG from 'react-inlinesvg';
    import { styled } from 'styled-components';
    
    const StyledSVG = styled(SVG).attrs({
        src: '/icons/menu.svg',
    })`
        width: ${({ $width }) => $width};
        height: ${({ $height }) => $height};
    
        > path {
            stroke: ${({ $color, theme }) => $color ?? theme.textColor};
        }
    
        ${({ $css }) => $css}
    `;
    
    const MenuIcon = (props) => <StyledSVG {...props} />;

    В этом случае ваш новый компонент MenuIcon больше не требует, чтобы src был предоставлен как пропс.

  2. Переопределение типов: Вы также можете расширить типы, чтобы сделать свойство src не обязательным в пользовательском интерфейсе, но оставить его обязательным в реализациях. Здесь вам нужно переопределить интерфейс, который используется в props:

    type CustomSVGProps = Omit<OriginalSVGProps, 'src'>;
    
    const StyledSVG = styled(SVG).attrs<CustomSVGProps>(props => ({
        src: '/icons/menu.svg',
        ...props,
    }))`
        /* ваши стили */
    `;
  3. Использование defaultProps: Альтернативно, вы могли бы установить src как defaultProps:

    StyledSVG.defaultProps = {
        src: '/icons/menu.svg',
    };

    В этом случае, если src не будет передан, компонент будет использовать заданное по умолчанию значение.

Заключение

Для решения проблемы с обязательным свойством src в вашем компоненте SVG из react-inlinesvg, важно переосмыслить подход к типизации, установлению пропсов или созданию обертки. Независимо от выбранного вами метода, этот подход поможет вам избавиться от ошибок компиляции и упростить использование вашего компонента.

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

Оцените материал
Добавить комментарий

Капча загружается...