Компонент высшего порядка с общими типами создания - PullRequest
2 голосов
/ 07 июня 2019

У меня есть универсальный тип объединения для выборки данных, который называется 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: Type '{data: T;} 'нельзя назначить типу' K '.

Когда я пытаюсь присвоить remote.data data из XComponent.

Здесь Вы найдете весь код, необходимый для воспроизведения проблемы.Есть ли способ исправить эти типы?

Ответы [ 2 ]

1 голос
/ 07 июня 2019

Тип параметра для HOC, XComponent, предполагает, что его свойства соответствуют некоторому типу K, который может содержать некоторые дополнительные свойства в дополнение к data.

Но тип props для HOC, IWithRemote<T>, имеет свойство remote, которое, как утверждается, имеет только data, когда kind равно Success, больше ничего.

Итак, когда вы визуализируете XComponent с

<XComponent data={remote.data} />

Где все остальные свойства в K, которые XComponent ожидает получить за props, должны быть получены?

В любом случае, если все, что нужно XComponent, объединяется с data в remote, когда kind равно Success, вы можете заявить, что это действительно так - вам просто нужно добавить этот параметр K в 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, передано ему, а не только data:

            case RemoteDataKind.Success:
                return <XComponent {...remote} />;
1 голос
/ 07 июня 2019

Вы могли бы просто сделать

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...