具有通用初始类型的高阶组件

时间:2019-06-07 07:54:18

标签: reactjs typescript higher-order-components

我有一个用于获取数据的通用联合类型,名为RemoteData,为此我试图创建一个更高阶的组件:

export interface IWithRemote<T> {
  remote: RemoteData<T>;
}

export interface IWithData<T> {
  data: T;
}

export function withRemoteData<T, K extends IWithData<T>>(XComponent: React.ComponentType<K>) {
  return class extends React.Component<IWithRemote<T>> {
    render() {
      const { remote } = this.props;
      switch (remote.kind) {
        case RemoteDataKind.NotAsked:
          return <div> nice not asked yet </div>;
        case RemoteDataKind.Loading:
          return <Spinner />;
        case RemoteDataKind.Success:
          return <XComponent data={remote.data} />
        case RemoteDataKind.Failure:
          return <div>daaaamn</div>;

        default:
          return assertNever(remote);
      }
    }
  };
}

但是这些类型不起作用。不确定我是否正在尝试做的事情,无论如何我都会得到

  

TS2322:键入'{data:T; }”不能分配给类型“ K”。

当我尝试将remote.data分配给data的{​​{1}}时。

Here,您会找到重现该问题所需的所有代码。有没有办法解决这些类型?

2 个答案:

答案 0 :(得分:1)

您可以简单地

export function withRemoteData<T>(
    XComponent: React.ComponentType<IWithData<T>>
) {
    return class extends React.Component<IWithRemote<T>> {
        render() {
            const { remote } = this.props;
            switch (remote.kind) {
                case RemoteDataKind.NotAsked:
                    return <div> nice not asked yet </div>;
                case RemoteDataKind.Loading:
                    return <div> spinnnnnner </div>;
                case RemoteDataKind.Success:
                    return <XComponent data={remote.data} />;
                case RemoteDataKind.Failure:
                    return <div>daaaamn</div>;

                default:
                    return assertNever(remote);
            }
        }
    };
}

https://codesandbox.io/s/react-typescript-playground-38bnw

答案 1 :(得分:1)

HOC的参数类型z<=64期望其属性符合某种类型的XComponent,该类型可能包含K之外的一些其他属性。

但是,HOC的data类型props具有IWithRemote<T>属性,当remote为{{1}时,该属性声明为仅具有data },没什么。

因此,当您使用

渲染kind
Success

XComponent预期从其<XComponent data={remote.data} /> 接收的K中所有其他属性应该来自哪里?

无论如何,如果XComponentpropsXComponent所需的所有内容与data中的remote一起出现,则可以声明确实如此-您只需将kind参数添加到SuccessK,然后将RemoteData联合成员声明为交集类型

IWithRemote

完整的类型是

Success

然后,在渲染 { kind: RemoteDataKind.Success; } & K 时,需要确保type RemoteData<T, K extends IWithData<T>> = | { kind: RemoteDataKind.NotAsked; } | { kind: RemoteDataKind.Loading; } | { kind: RemoteDataKind.Success; } & K | { kind: RemoteDataKind.Failure; error: Error; }; interface IWithRemote<T, K extends IWithData<T>> { remote: RemoteData<T, K>; } interface IWithData<T> { data: T; } export function withRemoteData<T, K extends IWithData<T>>( XComponent: React.ComponentType<K> ) { return class extends React.Component<IWithRemote<T, K>> { 中的所有内容都传递给它,而不仅仅是XComponent

remote