Компонент React Higher Order ожидает введенную поддержку при использовании, вызывает ошибку TypeScript

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

Код работает как положено машинописи не устраивает.

В моем TestContainer.tsx я делаю getQuotes реквизит, который будет введен HOC.

Но когда я использую упакованный экспортированный компонент в моем App.tsx, он жалуется, что я не указал реквизит, который вводится HOC.

Type error: Property 'getQuotes' is missing in type '{ message: string; }' but required in type 'Readonly<Pick<OwnProps & NetworkProps, "message" | "getQuotes">>'.  TS2741

    25 |
  > 26 |         <TestContainer message="lala" />
       |          ^
    27 |       </div>
    28 |     );
    29 |   }

Приложение.tsx:

      <div className="App">
        <TestContainer message="lala" />
      </div>

это мой ХОС

import * as React from "react";

interface Props {}

interface State {
  errors: Error[];
  isLoading: boolean;
}

export type FunctionMap = { [key: string]: (...args: any[]) => any };

export const withNetwork = <P extends Props>(
  PassedComponent: React.ComponentType<P>,
  calls: FunctionMap
) => {
  return class NetworkWrapper extends React.Component<
    Pick<P, Exclude<keyof P, keyof Props>>,
    State
  > {
    functionMap: FunctionMap;
    constructor(props: P) {
      super(props);

      this.functionMap = Object.keys(calls).reduce(
        (prev: FunctionMap, current: string) => ({
          ...prev,
          [current]: this.makeHandler(calls[current])
        }),
        {}
      );
    }
    state = { errors: [], isLoading: false };

    makeHandler = (func: (...orignalArgs: any) => any) => async (
      ...args: any[]
    ) => {
      try {
        this.setState({ isLoading: true });
        const result = await func(...args);
        this.setState({ isLoading: false });
        return result;
      } catch (error) {
        this.setState({ isLoading: false });
        this.setState(prev => ({ errors: [...prev.errors, error] }));
      }
    };

    handleDismissError = () => {
      this.setState((prev: State) => {
        const [first, ...errors] = prev.errors;
        return { errors };
      });
    };

    render() {
      const props = this.props as P;
      return (
        <div>
          {this.state.isLoading && <h3>LOADING</h3>}
          {this.state.errors.length > 0 && (
            <>
              <ul>
                {this.state.errors.map(error => (
                  // @ts-ignore
                  <li>{error.message}</li>
                ))}
              </ul>
              <button onClick={this.handleDismissError}>Dismiss</button>
            </>
          )}
          <div>
            <PassedComponent {...this.functionMap} {...props} />
          </div>
        </div>
      );
    }
  };
};

Это TestContainer, использующий HOC

import * as React from "react";
import axios from "axios";
import { withNetwork, FunctionMap } from "./NetworkWrapper";

interface OwnProps {
  message: string;
}

interface NetworkProps {
  getQuotes: (n: number) => Promise<any>;
}

interface State {
  body?: any;
}

class TestContainer extends React.Component<OwnProps & NetworkProps, State> {
  componentDidMount = async () => {
    const { getQuotes } = this.props;
    const data = await getQuotes(1234);
    data && this.setState({ body: data });
  };

  state = { body: undefined };
  render() {
    const { body } = this.state;
    const { message } = this.props;
    return (
      <div>
        <h1>{message}</h1>
        <section>
          <code>{JSON.stringify(body, null, 2)}</code>
        </section>
      </div>
    );
  }
}

const api = {
  getQuotes: async (n: number) => {
    console.warn({ n });
    const result = await axios.get(
      "http://example.com/quotes"
    );
    if (result.status === 200) {
      return result.data;
    } else {
      throw new Error("invalid response");
    }
  }
};

export default withNetwork(TestContainer, api);

person Esben von Buchwald    schedule 04.02.2019    source источник
comment
ты когда-нибудь это понял?   -  person baku    schedule 12.05.2020
comment
для меня это было решено, убедившись, что интерфейс был определен, а затем экспортирован в сам HOC, а затем импортированы определения интерфейса реквизита HOC.   -  person baku    schedule 12.05.2020


Ответы (1)


Ваша опора getQuotes определена как требуемая. Когда вы подписываете getQuotes как необязательный, он не выдает ошибку типа.

interface NetworkProps {
  getQuotes?: (n: number) => Promise<any>;
}

или вам нужно использовать свой TestContainer с getQuotes и message

<TestContainer message="....." getQuotes={.....}/>
person sdkcy    schedule 04.02.2019
comment
Да, необязательные реквизиты могут быть обходным путем. Но я думал, что это должно быть возможно сделать это по-другому. Точно так же, как когда компонент подключен к редуксу, а редукт отображает состояние и отправку в реквизит. Так что я ищу трюк, который заставляет машинописный текст знать, что обернутый TestContainer должен получать только свои собственные реквизиты, так как остальные будут введены. - person Esben von Buchwald; 06.02.2019