Как обрабатывать свойства, которые существуют в одной перегрузке, а не в другой? - PullRequest
0 голосов
/ 23 января 2019

Я использую React 16 и Typescript 3. Я создаю компонент, который возвращает кнопку или ссылку в зависимости от того, установлено свойство до или нет. Компонент может получить либо свойство - , либо onClick , оно не может принимать оба значения.

Я обнаружил проблему в репозитории TypeScript , которая точно описывает мою проблему, и кажется, что она исправлена ​​в версии 2.2, но каким-то странным образом она не работает.

Для этого я создал интерфейсы и использую их следующим образом:

interface GeneralProps {/* whatever here, it works */}
interface LinkProps extends GeneralProps { to: string }
interface ButtonProps extends GeneralProps { 
  onClick?: (e: React.MouseEvent<HTMLButtonElement>) => void 
  // onClick might be as well undefined
}

function Button (props: LinkProps | ButtonProps): JSX.Element {
  const Component: AnyStyledComponent = props.to ? Link : Button
  return (
    <Component to={props.to} onClick={props.onClick}>
      {props.children}
    </Component>
  )
}

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

function Button (props: LinkProps): JSX.Element
function Button (props: ButtonProps): JSX.Element {
  const Component: AnyStyledComponent = props.to ? Link : Button
  return (
    <Component to={props.to} onClick={props.onClick}>
      {props.children}
    </Component>
  )
}

Первая реализация функции Button, приведенной выше, выбрасывает обе ошибки, вторая - только первую:

Свойство 'to' не существует для типа 'LinkProps | ButtonProps. Свойство «to» не существует для типа «ButtonProps».

Свойство 'onClick' не существует для типа 'LinkProps | ButtonProps. Свойство «onClick» не существует для типа «LinkProps».

Чтобы избежать ошибок, я пришел с глупым обходным путем:

function Button (props: LinkProps | ButtonProps): JSX.Element {
  const properties = Object.keys(props)
  const to = properties.find((el) => el === 'to')
  const Component: AnyStyledComponent = to ? Link : Button
  return (
    <Component {...props}>
      {props.children}
    </Component>
  )
}

Однако это не решает мою проблему, потому что я все еще могу передать оба свойства в и onClick компоненту Button.

Есть ли в моем коде какая-то ошибка, которая мешает мне достичь своей цели, должен ли я подойти к этой проблеме под другим углом или это просто невозможно сделать?

1 Ответ

0 голосов
/ 23 января 2019

Благодаря ветке, опубликованной jcalz, я нашел решение, которое на самом деле работает так, как я хотел. Мое решение другое (я использую интерфейсы, а не типы), однако этот поток заставил меня задуматься об использовании типа never. Я использовал его и раньше, но как обязательное свойство, а затем машинопись потребовала передать значение, а когда вы его передали, машинопись потребовала удалить его. Никогда не типизированные свойства должны быть необязательными.

interface GeneralProps {/* whatever here, it works */}
interface LinkProps extends GeneralProps { 
  to: string
  onClick?: never
}
interface ButtonProps extends GeneralProps { 
  onClick?: (e: React.MouseEvent<HTMLButtonElement>) => void 
  to?: never
}
function Button (props: LinkProps | ButtonProps): JSX.Element { ... }

В текущем решении typcript всегда распознает, что оба типа, до и onClick , существуют для типа, не выдает ошибку, когда я вставляю одно из этих свойств, но бросает, когда я передаю оба свойства.

...