添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
首发于 KataKana
React 实现 forwardRef 的 TypeScript 泛型匿名函数组件

React 实现 forwardRef 的 TypeScript 泛型匿名函数组件

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 }) => { /* ... */ }

✔️ 上面这个方案是当时直接照猫画虎写好的,后来运行才发现报错,下面提供一种各种方面都更优秀的方法:

interface TranscriptProps<ItemT> extends FlatListProps<ItemT> { /* ... */ }
export type TranscriptComponent<ItemT = any> = (
  props: TranscriptProps<ItemT>,
  ref?: Ref<FlatList<ItemT>>
) => ReactElement | null