Как заставить TypeScript выводить типы через несколько компонентов высшего порядка в Typescript? - PullRequest
2 голосов
/ 03 октября 2019

Я конвертирую приложение React в Typescript, который использует множество шаблонов функционального программирования. Самым важным из этих шаблонов является способность объединять несколько компонентов более высокого порядка, чтобы получить расширенный компонент. Я хочу, чтобы Typescript выводил типы компонентов на каждом уровне и заканчивал компонентом, который я передаю, чтобы все типы HOC выше него.

Я пробовал этот код на3.5.0 и последняя версия Typescript. Что касается кода, я попытался сделать универсальное расширение нужных типов <T extends FooProps>, передав FC<T & BarProps> возвращаемому функциональному компоненту и стравливая вызовы HOC.

export const withFoo = <T>(Component: FC<T & FooProps>): FC<Omit<T, 'foo'>> => props => (
  <Component {...props as T} foo="foo" />
)

export const withBar = <T>(Component: FC<T & BarProps>): FC<Omit<T, 'bar'>> => props => (
  <Component {...props as T} bar="bar" />
)

export const EnhancedComponent = withFoo(
  withBar(({ bar, foo }) => { // bar exists and foo does not exist on type 'PropsWithChildren<BarProps>'
    console.log(bar) // types come through (bar: string)
    console.log(foo) // types don't come through (foo: any) :(
    return <div>woohoo</div> 
  }),
)

Я хочу типыпройти на каждом уровне HOC. В приведенном выше примере я хочу увидеть это в функциональном компоненте, который я передаю:

export const EnhancedComponent = withFoo(
  withBar(({ bar, foo }) => { // both exist on the component
    console.log(bar) // bar: string
    console.log(foo) // foo: string
    return <div>woohoo</div>
  }),
)

1 Ответ

1 голос
/ 03 октября 2019

Хорошее место для начала при поиске компонентов более высокого порядка - другие пакеты или @types пакеты.

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

Учитывая это, здесь есть одно потенциальное решение. Несколько моментов, на которые следует обратить внимание:

  • Предполагая, что вы хотите разрешить любой тип компонента (класс или функцию), возможно, вам нужен React.ComponentType.
  • Я стараюсь избегать приведений, но похоже, что это все еще недостаток (проблема) с TypeScript. Эти два вопроса выглядели актуально: # 28884 & # 28748
  • Omit добавлено для справки, потому что до того, как его не было до 3.5 (я былтестирование в Codesandbox, которое в настоящее время все еще находится на 3.3)
import * as React from "react";
import { render } from "react-dom";

// This exists in TypeScript 3.5+
type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;

interface FooProps {
  foo: string;
}

interface BarProps {
  bar: string;
}

export const withFoo = <Props extends FooProps>(
  Component: React.ComponentType<Props>
): React.ComponentType<Omit<Props, keyof FooProps>> => props => (
  <Component {...props as Props} foo="foo" />
);

export const withBar = <Props extends BarProps>(
  Component: React.ComponentType<Props>
): React.ComponentType<Omit<Props, keyof BarProps>> => props => (
  <Component {...props as Props} bar="bar" />
);

const WrappedComponent = ({ bar, foo, more }) => {
  console.log(more);
  console.log(bar);
  console.log(foo);
  return <div>woohoo</div>;
};

const EnhancedComponent = withFoo(withBar(WrappedComponent));

const App = () => <EnhancedComponent more="more" />;

const rootElement = document.getElementById("root");
render(<App />, rootElement);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...