类型 'typeof Row' 不可分配给类型 'ComponentType<ListChildComponentProps<any>> & ReactNode'。 TS2769

Type 'typeof Row' is not assignable to type 'ComponentType<ListChildComponentProps<any>> & ReactNode'. TS2769

我正在使用 react-window 组合一个无限滚动列表,但遇到打字稿构建错误。我搜索了堆栈溢出并修复了其他一些以前的错误,但我无法修复最后一个错误。

这是codesandbox中的代码: https://codesandbox.io/s/pedantic-leakey-bw5fv?file=/src/App.tsx

与此处 link 相同的代码副本:

import { PureComponent } from "react";
import { FixedSizeList as List } from "react-window";
import InfiniteLoader from "react-window-infinite-loader";
import AutoSizer from "react-virtualized-auto-sizer";

const LOADING = 1;
const LOADED = 2;
let itemStatusMap: any = {};

const isItemLoaded = (index: number) => !!itemStatusMap[index];
const loadMoreItems = (
  startIndex: number,
  stopIndex: number
): Promise<void> => {
  for (let index = startIndex; index <= stopIndex; index++) {
    itemStatusMap[index] = LOADING;
  }
  return new Promise((resolve) =>
    setTimeout(() => {
      for (let index = startIndex; index <= stopIndex; index++) {
        itemStatusMap[index] = LOADED;
      }
      resolve();
      console.log(Object.keys(itemStatusMap).length);
    }, 10)
  );
};

interface IRecipeProps {
  index: number;
  style: any;
}

interface IRecipeState {}

class Row extends PureComponent<IRecipeProps, IRecipeState> {
  render() {
    const { index, style } = this.props;
    let label;
    if (itemStatusMap[index] === LOADED) {
      label = `Row ${index}`;
    } else {
      label = "Loading...";
    }
    return (
      <div className="ListItem" style={style}>
        {label}
      </div>
    );
  }
}

export default function App() {
  return (
    <AutoSizer>
      {({ height, width }) => (
        <InfiniteLoader
          isItemLoaded={isItemLoaded}
          itemCount={50}
          loadMoreItems={loadMoreItems}
        >
          {({ onItemsRendered, ref }) => (
            <List
              className="List"
              height={height}
              itemCount={50}
              itemSize={30}
              onItemsRendered={onItemsRendered}
              ref={ref}
              width={width}
            >
              {Row}
            </List>
          )}
        </InfiniteLoader>
      )}
    </AutoSizer>
  );
}

错误:

Failed to compile

/home/user/code/frontend/src/components/Table/table2.tsx
TypeScript error in /home/user/code/frontend/src/components/Table/table2.tsx(72,15):
No overload matches this call.
  Overload 1 of 2, '(props: FixedSizeListProps<any> | Readonly<FixedSizeListProps<any>>): FixedSizeList<any>', gave the following error.
    Type 'typeof Row' is not assignable to type 'ComponentType<ListChildComponentProps<any>> & ReactNode'.
      Type 'typeof Row' is not assignable to type 'ComponentClass<ListChildComponentProps<any>, any>'.
        Construct signature return types 'Row' and 'Component<ListChildComponentProps<any>, any, any>' are incompatible.
          The types of 'props' are incompatible between these types.
            Type 'Readonly<IRecipeProps> & Readonly<{ children?: ReactNode; }>' is not assignable to type 'Readonly<ListChildComponentProps<any>> & Readonly<{ children?: ReactNode; }>'.
              Property 'data' is missing in type 'Readonly<IRecipeProps> & Readonly<{ children?: ReactNode; }>' but required in type 'Readonly<ListChildComponentProps<any>>'.
  Overload 2 of 2, '(props: FixedSizeListProps<any>, context: any): FixedSizeList<any>', gave the following error.
    Type 'typeof Row' is not assignable to type 'ComponentType<ListChildComponentProps<any>> & ReactNode'.  TS2769

    70 |               width={width}
    71 |             >
  > 72 |               {Row}
       |               ^
    73 |             </List>
    74 |           )}
    75 |         </InfiniteLoader>

你只需要添加 data 属性 到 Row 组件道具。

import React, { PureComponent } from "react";
import { FixedSizeList as List } from "react-window";
import InfiniteLoader from "react-window-infinite-loader";
import AutoSizer from "react-virtualized-auto-sizer";

const LOADING = 1;
const LOADED = 2;
let itemStatusMap: any = {};

const isItemLoaded = (index: number) => !!itemStatusMap[index];
const loadMoreItems = (
    startIndex: number,
    stopIndex: number
): Promise<void> => {
    for (let index = startIndex; index <= stopIndex; index++) {
        itemStatusMap[index] = LOADING;
    }
    return new Promise((resolve) =>
        setTimeout(() => {
            for (let index = startIndex; index <= stopIndex; index++) {
                itemStatusMap[index] = LOADED;
            }
            resolve();
            console.log(Object.keys(itemStatusMap).length);
        }, 10)
    );
};

interface IRecipeProps {
    index: number;
    style: any;
    data: Array<unknown> // you need to add `data` property
}

class Row extends PureComponent<IRecipeProps> {
    render() {
        const { index, style } = this.props;
        let label;
        if (itemStatusMap[index] === LOADED) {
            label = `Row ${index}`;
        } else {
            label = "Loading...";
        }
        return (
            <div className="ListItem" style={style}>
                {label}
            </div>
        );
    }
}

export default function App() {
    return (
        <AutoSizer>
            {({ height, width }) => (
                <InfiniteLoader
                    isItemLoaded={isItemLoaded}
                    itemCount={50}
                    loadMoreItems={loadMoreItems}
                >
                    {({ onItemsRendered, ref }) => (
                        <List
                            className="List"
                            height={height}
                            itemCount={50}
                            itemSize={30}
                            onItemsRendered={onItemsRendered}
                            ref={ref}
                            width={width}
                        >
                            {Row}
                        </List>
                    )}
                </InfiniteLoader>
            )}
        </AutoSizer>
    );
}

Playground