You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用react-window构建无限滚动列表时遇到TypeScript编译错误TS2769的求助

解决react-window + TypeScript的无限滚动列表编译错误

这个错误的核心原因是你的Row组件的props类型没有匹配react-window的FixedSizeList要求的子组件props类型。具体来说,FixedSizeList会给它的子组件传递三个必填属性:index、style和data,但你的IRecipeProps只定义了前两个,缺少data,所以TypeScript抛出了类型不兼容的错误。

下面是具体的修复步骤:

步骤1:导入react-window的子组件props类型

首先从react-window中导入ListChildComponentProps类型,这个类型定义了列表子组件必须接收的props:

import { FixedSizeList as List, ListChildComponentProps } from "react-window";

步骤2:调整Row组件的props类型

你有两种方式来修正props类型:

方式一:让自定义props接口继承ListChildComponentProps

修改你的IRecipeProps接口,让它继承ListChildComponentProps(如果未来需要给Row添加额外props,这种方式更灵活):

interface IRecipeProps extends ListChildComponentProps<any> {
  // 这里可以添加你需要的额外props,当前场景不需要的话留空即可
}

class Row extends PureComponent<IRecipeProps, IRecipeState> {
  // ... 原有render逻辑保持不变
}

方式二:直接使用ListChildComponentProps作为props类型

如果不需要自定义额外props,也可以直接把Row的props类型设置为ListChildComponentProps<any>:

class Row extends PureComponent<ListChildComponentProps<any>, IRecipeState> {
  render() {
    const { index, style } = this.props;
    // 不需要用到data属性也没关系,只要类型上兼容即可
    let label;
    if (itemStatusMap[index] === LOADED) {
      label = `Row ${index}`;
    } else {
      label = "Loading...";
    }
    return (
      <div className="ListItem" style={style}>
        {label}
      </div>
    );
  }
}

为什么这样能解决问题?

react-window的FixedSizeList组件要求它的子组件必须是符合ComponentType<ListChildComponentProps<any>>类型的组件,这个类型强制要求组件接收data、index、style这三个props。通过让你的Row组件的props类型继承或直接使用这个类型,就满足了TypeScript的类型检查要求,编译错误也就消失了。

修改后的完整代码示例:

import { PureComponent } from "react";
import { FixedSizeList as List, ListChildComponentProps } 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 extends ListChildComponentProps<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>
  );
}

内容的提问来源于stack exchange,提问作者Greg

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 08:04:04