Использование стилизованных компонентов «как» с машинописью - PullRequest
10 голосов
/ 01 июля 2019

В настоящее время я создаю библиотеку шаблонов, в которой я создал компонент Button, используя React и styled-components. Основываясь на компоненте Button, я хочу, чтобы все мои компоненты Link s выглядели одинаково и получали абсолютно одинаковые реквизиты. Для этой цели я использую опору as из styled-components, которая позволяет мне использовать уже построенный элемент в качестве другого тега или компонента.

Компонент кнопки

import * as React from 'react'
import { ButtonBorderAnimation } from './ButtonAnimation'
import { ButtonProps, ButtonVariant } from './Button.types'
import { ButtonBase, LeftIcon, RightIcon } from './Button.styled'

function Button({
  variant = ButtonVariant.Filled,
  children,
  leftIcon = null,
  rightIcon = null,
  ...props
}: ButtonProps): JSX.Element {
  return (
    <ButtonBase variant={variant} {...props}>
      {variant !== ButtonVariant.Ghost ? (
        <ButtonBorderAnimation {...props} />
      ) : null}
      {leftIcon ? <LeftIcon>{leftIcon}</LeftIcon> : null}
      {children}
      {rightIcon ? <RightIcon>{rightIcon}</RightIcon> : null}
    </ButtonBase>
  )
}

export default Button

Типы кнопок

export interface ButtonProps {
  children: React.ReactNode
  variant?: 'filled' | 'outlined' | 'ghost'
  size?: 'small' | 'regular'
  underlinedOnHover?: boolean
  leftIcon?: React.ReactNode
  rightIcon?: React.ReactNode
  inverse?: boolean
}

export enum ButtonVariant {
  Filled = 'filled',
  Outlined = 'outlined',
  Ghost = 'ghost',
}

export enum ButtonSize {
  Small = 'small',
  Regular = 'regular',
}

Компонент связи

import * as React from 'react'
import Button from '../Button/Button'
import { Link as LinkRouter } from 'react-router-dom'
import { LinkProps } from './Link.types'

function Link({ to, ...props }: LinkProps): JSX.Element {
  return <Button to={to} as={LinkRouter} {...props} />
}

export default Link

Типы ссылок

import { ButtonProps } from '../Button/Button.types'
import { LinkProps } from 'react-router-dom'

type RouterLinkWithButtonProps = ButtonProps & LinkProps

export interface LinkProps extends RouterLinkWithButtonProps {}

Когда я делаю вышеизложенное, эта проблема возникает у нас ...

Property 'to' does not exist on type 'IntrinsicAttributes & ButtonProps'.

... что имеет смысл, потому что у кнопки нет опоры to, которая требуется для компонента Link из react-router-dom.

Как вы подойдете к чему-то подобному? В тех случаях, когда при использовании Button реквизит to даже не должен быть в типе, а при использовании Link должен потребоваться to.

Использует

<Button>Hello</Button>
<Link to="/somewhere">Hello</Link>

1 Ответ

0 голосов
/ 05 июля 2019

Это должно работать.

function Link(_props: LinkProps): JSX.Element {
  const props = { as: LinkRouter, ..._props };
  return <Button {...props} />
}

Обратите внимание, что TypeScript применяет строгие проверки литерала объекта , которые можно ослабить, предварительно назначив литерал объекта переменной вместо прямой передачи его, например, в качестве аргумента функции, что согласуется с Реагирует на поведение компонентов при подборе реквизита.

declare function foo(arg: { a: number }): void;

foo({ to: '', a: 1 }); // error

const arg = { to: '', a: 1 };
foo(arg); // no error
...