Как связать родовые типы, определенные между функциями высшего порядка? - PullRequest
0 голосов
/ 17 ноября 2018

Я создаю энхансер магазина Redux, который принимает функцию для сериализации состояния Redux.Я создам магазин и настрою подписку на изменения - при каждом изменении я буду сериализовывать состояние.Для этого MCVE я игнорирую аспект подписки и просто немедленно вызываю функцию сериализации.

Однако из-за природы функции более высокого порядка я не могу соотнести мой универсальный тип для состояния (необходимого для функции сериализации) с универсальным типом, возвращаемым создателем магазина:

// Copied and reduced from Redux 4.0.1

type Reducer<S = any> = (
  state: S | undefined,
) => S

type DeepPartial<T> = { [K in keyof T]?: DeepPartial<T[K]> }

interface Store<S = any> {
  getState(): S
}

type StoreEnhancer<Ext = {}, StateExt = {}> = (
  next: StoreEnhancerStoreCreator
) => StoreEnhancerStoreCreator<Ext, StateExt>

type StoreEnhancerStoreCreator<Ext = {}, StateExt = {}> = <
  S = any,
>(
  reducer: Reducer<S>,
  preloadedState?: DeepPartial<S>
) => Store<S & StateExt> & Ext

// My reduced code

interface Config<S> {
  serialize: (state: S) => string;
}

const storage = <S>(config: Config<S>): StoreEnhancer => createStore => (reducer, preloadedState) => {
  const { serialize } = config;

  const theStore = createStore(reducer, preloadedState);

  const state = theStore.getState();
  const serializedState = serialize(state);

  return theStore;
}

( детская площадка )

Ошибка:

const serializedState = serialize(state);
                                  ^~~~~

Argument of type 'S & {}' is not assignable to parameter of type 'S'.

Сообщение об ошибке раздражает, потому что я почти уверен, что два S не связаны;изменение определения в StoreEnhancerStoreCreator для использования X вместо S изменяет это сообщение об ошибке.

Как я могу связать свой параметр универсального типа с параметром универсального, определенным в StoreEnhancerStoreCreator?

Ответы [ 3 ]

0 голосов
/ 18 ноября 2018

Я согласен с проблемой, указанной @ matt-mccutchen. StoreEnhancerStoreCreator - универсальная функция, поэтому (reducer, preloadedState) => { - универсальная функция с аргументом универсального типа S, поэтому компилятор сообщает о несовместимости между двумя S типами.

Решение, которое я бы предложил, состояло бы в том, чтобы StoreEnhancerStoreCreator не было универсальным, из того, что я могу сказать, редуктор и полезная нагрузка должны иметь тот же аргумент универсального типа, что и Config. Это решение требует добавления дополнительного параметра типа в StoreEnhancerStoreCreator и StoreEnhancer:

type Reducer<S = any> = (
  state: S | undefined,
) => S

type DeepPartial<T> = { [K in keyof T]?: DeepPartial<T[K]> }

interface Store<S = any> {
  getState(): S
}

type StoreEnhancer<S, Ext = {}, StateExt = {}> = (
  next: StoreEnhancerStoreCreator<S>
) => StoreEnhancerStoreCreator<S, Ext, StateExt>

type StoreEnhancerStoreCreator<S, Ext = {}, StateExt = {}> = (
  reducer: Reducer<S>,
  preloadedState?: DeepPartial<S>
) => Store<S> & Ext

// My Code

interface Config<S> {
  serialize: (state: S) => string;
}

const storage = <S>(config: Config<S>): StoreEnhancer<S> => createStore => (reducer, preloadedState) => {
  const { serialize } = config;

  const theStore = createStore(reducer, preloadedState);

  const state = theStore.getState();
  const serializedState = serialize(state);

  return theStore;
}
0 голосов
/ 18 ноября 2018

Ответ Тициана Черникова-Драгомира поставил меня на правильный путь:

Это решение требует добавления дополнительного параметра типа в StoreEnhancerStoreCreator и StoreEnhancer

Однако соответствующий параметр типа уже существует;Я просто не понимал, как правильно его использовать.В частности, StoreEnhancer возвращает StoreEnhancerStoreCreator с параметрами типа по умолчанию.Если я вместо этого установлю параметры типа, я теперь знаю, какое состояние будет возвращено:

const storage = <S>(config: Config<S>): StoreEnhancer =>
  (createStore: StoreEnhancerStoreCreator<{}, S>) =>
  //            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ set this type
    (reducer, preloadedState) => {
0 голосов
/ 17 ноября 2018

Проблема в том, что storage объявляется (косвенно, через StoreEnhancer), возвращая StoreEnhancerStoreCreator, что является универсальной функцией, которая должна работать для всех S.Тем не менее, данный вызов storage создает создателя магазина, который работает только для одного S: S из config, который был пройден.

Мне кажется, что единственный способ, которым вымог бы создать StoreEnhancerStoreCreator, если бы вы начали с функции serialize, которая сама была обобщенной в S.Я не уверен, имеет ли это смысл в вашем сценарии.Возможно, кто-то, знакомый с Redux, лучше поймет, что делать.

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