react-native 实现的 FlatList 组件使用了泛型组件的模式:
export class FlatList<ItemT = any> extends React.Component<FlatListProps<ItemT>>
这里我想要包装 FlatList 实现一些自己的功能,需要继承修改来自 react-native 的类型声明,还要保证代码风格与项目内其它的组件保持一致,那么它的格式应该类似:
interface TranscriptProps { /* ... */ }
const Transcript: React.FC<TranscriptProps> = (props) => { /* ... */ }
这里的 FlatList 需要一个泛型 ItemT 来提供对内部渲染的列表项目的类型提示,但使用了 React.FC 声明类型的函数组件却不能再添加泛型声明了,最后是在 stackoverflow 上找到了一篇解答,里面提供了一种不错的方法。
大概的解决方法就是将 React.FC 进行等效替换:
React.FC<P = {}>
基本等效于:
<P = {}>(props: PropsWithChildren<P>, context?: any) => ReactElement | null
在 P 的外层直接包裹 FlatListProps,于是传入泛型的目标从 Props 接口变成了 FlatListProps 内部列表项目的接口,即 { data: P }。
所以开头的代码改写之后就变成了:
interface TranscriptProps<ItemT> extends FlatListProps<ItemT> { /* ... */ }
const Transcript: <ItemT = any>(
props: TranscriptProps<ItemT>
) => ReactElement | null = (props) => { /* ... */ }
如果还需要使用 forwardRef 的话,这里有另一篇问答提到了相应的解决方法。回答中提到了三种解决方法,这里我选择自定义一个 ref 的 prop:
interface TranscriptProps<ItemT> extends FlatListProps<ItemT> { /* ... */ }
const Transcript: <ItemT = any>(
props: TranscriptProps<ItemT> & { ref: Ref<FlatList> }
) => ReactElement | null = ({ ref, ...props }) => { /* ... */ }