Безопасное обращение с опорами функциональных компонентов, введенными HOC - PullRequest
1 голос
/ 20 марта 2019

TL; DNR: Я использую TypeScript 3.3.3.Есть ли лучший способ объявить нужные мне реквизиты, которые вводятся из HOC, не делая их видимыми для кода, потребляющего мой компонент?


Рассмотрим базовый компонент, украшенный withNamespaces HOC.Используемая библиотека и HOC произвольны, я столкнулся с этой проблемой со всеми компонентами, которые следуют этому шаблону.Это также небольшая проблема с компонентами класса, но я сосредоточусь на функциях здесь.

// MyComponent.tsx
import * as React from 'react'
import { withNamespaces, WithNamespaces } from 'react-i18next'


const MyComponent: React.FunctionalComponent = ({ children, t }) => (
  <a title={t('my translated text')}>{children}</a>
)

export default withNamespaces('my-component')(MyComponent)

У меня есть второй файл, который содержит тесты для моего компонента.

// MyComponent.spec.tsx
import * as React from 'react'
import { shallow } from 'enzyme'
import MyComponent from './MyComponent'

it('should render', () => {
   const wrapper = shallow(<MyComponent>Test</MyComponent>)

   expect(wrapper.toExist()).toBeTruthy()
})

Теперь это не скомпилируется, потому что t не определено в моих реквизитах.Я могу попытаться исправить это несколькими способами.В этом примере сторонняя библиотека предоставляет нам тип WithNamespaces, который определяет t, и кучу других вещей, которые withNamespaces внедряет в наш компонент, которые мы можем использовать как или объединить с нашим определением типа props.

 const MyComponent: React.FunctionalComponent<WithNamespaces> = ({children, t}) => ( // ...

Теперь MyComponent компилируется и дает мне хорошую безопасность типов в отношении моих возможных реквизитов.Тем не менее, теперь мой тестовый файл раздражен, потому что я не предоставил значения для реквизитов, ожидаемых определением компонента, например t.Тем не менее, мы знаем, что это будет внедрено HOC, поэтому создание макета или предоставление этому реквизиту некоторого мусора просто сбивает с толку и лишнюю дополнительную работу для решения проблем с типами.

// type is missing the following properties from WithNamespaces: t, etc., etc.
const wrapper = shallow(<MyComponent>Test</MyComponent>)

IЯ могу выдумать это, сделав реквизиты моего компонента частичными FunctionalComponent<Partial<WithNamespaces>>, но теперь я должен условно проверить те реквизиты, которые мне нужны, или использовать t! (оператор ненулевого утверждения), и они кажутся излишне раздражающими, таят мозгилюди, плохо знакомые с TS, и кажутся немного вонючими.

Я также могу просто бросить реквизиты внутри своей функции рендеринга (или в классах, любой метод, который обращается к реквизитам), чтобы скрыть введенные реквизиты от моих потребителей:1029 *

const MyComponent: React.FunctionalComponent = (props) => {
  const { children, t } = props as WithNamespaces
  return (
    <a title={t('my translated text')}>{children}</a>
  )
}

Это немного волнисто и не элегантно.Существует множество других способов, таких как приведение к любому и обратно к чему-то, что не ссылается на WithNamespaces и т. Д., Но, безусловно, есть лучший способ сделать это?

Разное

withNamespace действительно имеет определение, которое использует шаблон Omit для исключения реквизита в WithNamespaces из возвращаемого типа, но это, похоже, не работает, по крайней мерес функциональными компонентами.

...