【问题标题】:React + Typescript Higher Order Function "not assignable to type" errorReact + Typescript 高阶函数“不可分配给类型”错误
【发布时间】:2019-07-01 18:42:01
【问题描述】:

我正在尝试在 typescript 中为 React 编写一个更高阶的函数: (1) 要求被包装的组件具有一定的属性 (2) 允许在包装器上设置被包装组件的属性 (3) 具有特定于包装器的属性

我大部分时间都在工作,但是当我在包装我的组件的匿名类上设置默认属性时,我从 typescript 收到一个我无法解决的错误。

我得到的错误是:

src/withContainer.tsx:33:3 - error TS2322: Type 'typeof (Anonymous class)' is not assignable to type 'ComponentClass<P & ContainerProps, any>'.
  Types of property 'defaultProps' are incompatible.
    Type '{ loading: Element; }' is not assignable to type 'Partial<P & ContainerProps>'.

 33   return class extends React.Component<P & ContainerProps, ContainerState> {
      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 34     // Why does typescript say this is an error?
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
... 
 80     }
    ~~~~~
 81   };
    ~~~~

这是我正在尝试做的一个示例:

import * as React from "react";

/**
 * Properties specific to the container component.
 */
export interface ContainerProps {
  /* eslint-disable @typescript-eslint/no-explicit-any */
  loading: React.ReactElement<any>;
}

export interface ContainerState {
  data: {};

  initialized: boolean;
}

/**
 * Components being wrapped need a putData function on them.
 */
export interface PuttableProps {
  /**
   * Put data into state on the parent component.
   *
   * @param data Data to be put into state.
   */
  putData(data: object): void;
}

/* eslint-disable max-lines-per-function */
export function withContainer<P>(
  WrappedComponent: React.ComponentType<P & PuttableProps>
): React.ComponentClass<P & ContainerProps> {
  return class extends React.Component<P & ContainerProps, ContainerState> {
    // Why does typescript say this is an error?
    static defaultProps = {
      loading: <React.Fragment />
    };

    state: ContainerState = {
      initialized: false,
      data: {}
    };

    /**
     * After mounting, simulate loading data and mark initialized.
     */
    componentDidMount(): void {
      // Simulate remote data load, 2 minutes after we mounted set initialized to true
      setTimeout(() => {
        this.setState({
          initialized: true
        });
      }, 2000);
    }

    /**
     * Set data as state on the parent component.
     */
    private putData = (data: object): void => {
      this.setState({ data });
    };

    /**
     * Render the wrapped component.
     */
    render(): React.ReactNode {
      // If we haven't initialized the document yet, don't return the component
      if (!this.state.initialized) {
        return this.props.loading;
      }

      // Whatever props were passed from the parent, our data and our putData function
      const props = {
        ...this.props,
        ...this.state.data,
        putData: this.putData
      };

      return <WrappedComponent {...props} />;
    }
  };
}

export class ClickCounter extends React.Component<
  PuttableProps & { count: number },
  {}
> {
  static defaultProps = {
    count: 0
  };

  increment = () => {
    this.props.putData({ count: this.props.count + 1 });
  };

  render(): React.ReactNode {
    return (
      <div>
        <h1>{this.props.count}</h1>
        <button onClick={this.increment}>Increment</button>
      </div>
    );
  }
}

它可以像这样被利用:

import React from "react";
import ReactDOM from "react-dom";
import { withContainer, ClickCounter } from "./withContainer";

const WrappedClickCounter = withContainer(ClickCounter);
const component = (
  <WrappedClickCounter count={0} loading={<div>Loading...</div>} />
);

ReactDOM.render(component, document.getElementById("root"));

我尝试了一些变体,包括让 P 扩展 ContainerProps,但似乎没有任何效果。

我正在使用打字稿 3.3.1。

【问题讨论】:

    标签: javascript reactjs typescript higher-order-functions higher-order-components


    【解决方案1】:

    你解决过这个问题吗?我在您返回组件的那一行,您是否尝试过使用 Partial?:

    return class extends React.Component<P & ContainerProps...
    

    你可以试试这个吗?

    return class extends React.Component<Partial<P & ContainerProps>....
    

    【讨论】:

      【解决方案2】:

      正如错误所说,您的 defaultProps 与您的 ContainerProps 类型不匹配。具体来说,在ContainerProps 中,您有{ isLoading: ReactElement&lt;any&gt; },但您的defaultProps{ loading: Element } 类型。

      我建议您将ContainerProps 定义为:

      import type { ReactNode } from 'react';
      
      export interface ContainerProps {
        isLoading: ReactNode
      }
      

      【讨论】:

        猜你喜欢
        • 2020-05-01
        • 2020-11-09
        • 1970-01-01
        • 2022-08-23
        • 2021-10-17
        • 2020-03-26
        • 2012-10-25
        • 2016-06-24
        • 1970-01-01
        相关资源
        最近更新 更多