Правильная типизация для HigherOrderComponents с перекомпоновкой и машинописью - PullRequest
0 голосов
/ 03 января 2019

В настоящее время я пытаюсь перекомпоноваться в мою базу кода реакции.Поэтому я пытался заставить некоторые базовые вещи работать, и у меня это получилось, но я не совсем уверен, если это правильный способ, которым рекомпозиция предназначена для работы.

Итак, у меня есть следующий код:

interface Value {
  value: string
}

interface Loading {
  loading: boolean
}

const TestComponent = (props: Value) => <div>Value: {props.value}</div>
const LoadingComponent = () => <div>Loading ...</div>

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

ТакЯ использовал branch функцию перекомпоновки

const withLoading = branch<Loading>(
  ({loading}) => loading, 
  renderComponent(LoadingComponent)
) 

Теперь, когда я использую withLoading на любой Компонент без реквизита , я могу установить загрузочную опору на них.

const EnhancedCompWithLoading = withLoading(SomeCompWithoutProps)

render() {
  return <EnhancedCompWithLoading loading={this.state.loading} />
}

Это прекрасно работает для меня, настоящая проблема начинается при попытке использовать это с компонентами с реквизитом.Когда я пытаюсь сделать это следующим образом:

const TestWithLoading = withLoading(TestComponent)

render() {
  return <TestWithLoading value="testVal" loading={this.state.loading} />
}

Я получаю сообщение об ошибке TS2339: Property 'value' does not exist on type 'IntrinsicAttributes & IntrinsicClassAttributes<Component<Loading, any, any>> & Readonly<{ children?: ReactNode; }> & Readonly<Loading>'.

Итак, я посмотрел определение типа в @ types / Recompose up.branch<TOutter> возвращает ComponentEnhancer<any,TOutter>.Что я понимаю, я хочу иметь возможность предоставить any компонент, а универсальный <TOutter> таков, что результирующий компонент знает о необходимых реквизитах для тестовой функции.Это также работает без дополнительных реквизитов.

Однако определение типа для ComponentEnhancer выглядит так (перекомпоновать 0.30.2):

interface ComponentEnhancer<TInner, TOutter> {
  (component: Component<TInner>): ComponentClass<TOutter>
}

Итак, ComponentEnhancer<any, Loading>, который я получил от предыдущегоbranch функция вернет ComponentClass<Loading>.Однако <TInner> компонента, который я предоставляю ComponentEnhancer, будет отброшен, и я не могу использовать свои реквизиты Value в расширенном компоненте.

Итак, мой вопрос здесь, я делаю это просто неправильно,Есть ли лучший способ достичь этого (с перекомпоновкой).Или это просто ошибка в TypeDeclaration, так как изменение возврата ComponentEnhancer на ComponentClass<TOutter & TInner> исправляет все для меня.Есть мысли по этому поводу?

1 Ответ

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

Я не знаком с branch и recompose, но если это просто проблема с печатанием, мы можем ее исправить.

Проблема в том, что тип для branch не очень хорош. Если цель состоит в том, чтобы переслать свойства упакованного компонента в HOC и добавить в HOC реквизиты, явно набранные в branch, тогда лучшим типом результата будет:

type BetterComponentEnhancer<TOutter> = {
    <TInner>(component: React.ComponentType<TInner>): React.ComponentClass<TInner & TOutter>
}

С этим типом это будет работать:

const withLoading = branch<Loading>(
    ({ loading }) => loading,
    renderComponent(LoadingComponent)
)as unknown as BetterComponentEnhancer<Loading>

type BetterComponentEnhancer<TOutter> = {
    <TInner>(component: React.ComponentType<TInner>): React.ComponentClass<TInner & TOutter>
}

const TestWithLoading = withLoading(TestComponent)

function render() {
    return <TestWithLoading value="testVal" loading={true} />
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...