Как правильно ввести HOC в Typescript?

#javascript #reactjs #typescript

#javascript #reactjs #typescript

Вопрос:

Я получаю сообщение об отсутствии реквизитов в type, если я пытаюсь использовать реквизит, переданный из HOC.

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

Это мое решение:

 interface INavigationContext {
  componentId?: string;
}

interface IAddNavigationContextProps {
  navigation: INavigationContext;
}

export function addNavigationContext<P extends object >(
  Component: React.ComponentType<P>,
): React.ComponentType<P amp; IAddNavigationContextProps> {
  const WrappedComponent: React.ComponentType<P amp; IAddNavigationContextProps> = (props: P) => (
    <NavigationContext.Consumer>
      {(navigationState: INavigationContext) => (
        <Component {...props as P} navigation={navigationState} />
      )}
    </NavigationContext.Consumer>
  );

  WrappedComponent.displayName = `addNavigationContext(${getDisplayName(WrappedComponent)})`;

  return WrappedComponent;
}
  

Это ошибка, которую я получаю:

 Property 'navigation' does not exist on type 'Readonly<{}> amp; Readonly<{ children?: ReactNode; }>'.

  

Я ожидаю, что если обернуть компонент следующим образом:
addNavigationContext(MyComponent)

тогда я не получаю ошибок типа, если использую this.props.navigation внутри MyComponent

Ответ №1:

Во-первых, ваш HOC должен получить компонент, который ожидает свой собственный Props и IAddNavigationContextProps

 Component: React.ComponentType<P amp; IAddNavigationContextProps>
  

Во-вторых, ваш HOC должен возвращать компонент, который ожидает только свой собственный Props

 React.ComponentType<P>
  

Собрать воедино

 export function addNavigationContext<P = {}>(
    Component: React.ComponentType<P amp; IAddNavigationContextProps>,
): React.ComponentType<P> {
    const WrappedComponent: React.FC<P> = props => (
        <NavigationContext.Consumer>
            {(navigationState: INavigationContext) => <Component {...props} navigation={navigationState} />}
        </NavigationContext.Consumer>
    );

    WrappedComponent.displayName = `addNavigationContext(${getDisplayName(WrappedComponent)})`;

    return WrappedComponent;
}

const MyComponent = addNavigationContext(({ children, navigation }) => <p>Magic</p>);
  

Комментарии:

1.итак, это означает, что я в любом случае должен объявить navigation prop в MyComponent интерфейсе, не так ли? потому что я, как class MyComponent extends Component<IProps> {} addNavigationContext(MyComponent) я думал, можно было бы избежать navigation ввода в каждом компоненте, использующем HOC, если HOC был введен правильно.

2. @StefanoCerelli Если вы не хотите указывать его в интерфейсе, вам нужно написать его встроенным, как я сделал в нижней части моего примера.