如何为React HoC编写类型定义

时间:2018-09-20 20:52:08

标签: reactjs typescript higher-order-components

我有一个高阶组件为我处理Firestore数据。我对打字稿还很陌生,但在按我希望的方式工作时遇到了麻烦。

Here are the full files + some extra ts definitions

我有几个问题:

React.Component无法推断类型定义:

type WithFirestoreHoC<Props = {}> = (
  config: WithFirestoreConfig<Props>,
) => (
  WrappedComponent: ComponentType<WithFirestore & Props>,
) => ComponentClass<Props, { error: Error; queries: {}; loaded: boolean }>;

const withFirestore: WithFirestoreHoC = ({
  queries,
  props: propPickList,
  loading: { delay = 200, timeout = 0 } = {},
}) => WrappedComponent =>
  class WithFirestoreConnect extends Component { ... }

configWrappedComponent正在获取其类型定义(分别为WithFirestoreConfig + ComponentType<WithFirestore & Props>

但是,WithFirestoreConnect并不暗示它应该是ComponentClass<Props, { error: Error; queries: {}; loaded: boolean }>

我不介意两次定义状态,但这并不能帮助我将Propstype WithFirestoreHoC<Props = {}>转移到class WithFirestoreConnect extends Component<Props, { error: Error; queries: {}; loaded: boolean }> { ... },因为它找不到Props

如何创建动态选择列表

WithFirestoreConfig的一部分定义了配置对象具有传递到WrappedComponent的道具列表

WrappedComponent: ComponentType<WithFirestore & Props>, 应该真的是 WrappedComponent: ComponentType<WithFirestore & Pick<Props, config.propsPickList>,

有没有一种方法可以告诉打字稿您在config.propsPickList中提供的内容将决定WrappedComponent应该拥有哪些道具?

推断Firestore类型

Firestore查询响应有两种类型,分别是“文档”和“集合/查询”。如果可以在config.queries中将它们定义为这样的话,那将是惊人的:

{ queries: { 
    docQuery: myDocument as DocumentReference<docDataType>, 
    collectionQuery: myDocument as CollectionReference<docDataType>,  
} }

因此WrappedComponent可以知道在另一端是否需要查询或文档数据结构。

这似乎超级复杂,因此我在这里有一个简单的示例(这是创建单个订阅的快捷方式),至少可以成为实现所需目标的好垫脚石:

export const withFirestoreDocument: <
  DataType = firestore.DocumentData,
  Props = {}
>(
  query: FirestoreQueryable<DataType>,
) => (
  WrappedComponent: ComponentType<DocumentSnapshotExpanded<DataType>>,
) => WithFirestoreHoC<Props> = query => WrappedComponent =>
  withFirestore({ queries: { _default: query } })(
    mapProps<
      DocumentSnapshotExpanded<DataType> & Props,
      { _default: DocumentSnapshotExpanded<DataType> } & Props
    >(({ _default, ...props }) => ({ ...props, ..._default }))(WrappedComponent),
  );

但是由于无法从函数的类型定义中提取mapProp的类型定义,我被困在这里了……什么是正确的方法?

1 个答案:

答案 0 :(得分:1)

React.Component无法推断类型定义:使import React from "react"; import PlayerAPI from "../api"; import { Link } from "react-router-dom"; export default ({ match: { params } }) => { const player = PlayerAPI.get(parseInt(params.id, 10)); return !player ? ( <div style={{ padding: "0px 20px" }}> Sorry, but the player was not found </div> ) : ( <div style={{ padding: "0px 20px" }}> <h1> {player.name} (#{player.number}) </h1> <h2>Position: {player.position}</h2> <Link to="/roster">Back</Link> </div> ); }; 成为函数的类型参数而不是类型别名,然后在定义Props时声明它。

如何创建动态选择列表::为选择列表元素的并集添加withFirestore类型的参数。当您让TypeScript在调用站点上推断PL时,这将做正确的事情,尽管调用者有可能通过指定PL为并集类型(包括不在实际位置中的元素)来产生不合理的行为。列表。

推断Firestore类型:我不确定您要使用PL的去向。您可以使用另一个withFirestoreDocument类型的参数以及一些映射类型和条件类型来执行此操作,以从Q生成注入的道具的类型。

这是我对Q的修订,其中包含所有新功能,一些无关的修补程序以使其可以在我的环境中进行编译,并在底部添加了一个示例(可能应该放在单独的文件中):

withFirestore.tsx