如何关联高阶函数之间定义的泛型类型?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何关联高阶函数之间定义的泛型类型?相关的知识,希望对你有一定的参考价值。

我正在创建一个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;
}

(Qazxswpoi)

错误是:

playground

错误消息令人讨厌,因为我很确定这两个const serializedState = serialize(state); ^~~~~ Argument of type 'S & {}' is not assignable to parameter of type 'S'. 是无关的;更改S中的定义以使用StoreEnhancerStoreCreator而不是X更改此错误消息。

如何将我的泛型类型参数与S上定义的泛型参数相关联?

答案

我同意@ matt-mccutchen发现的问题。 StoreEnhancerStoreCreator是一个泛型函数,因此StoreEnhancerStoreCreator是一个带有(reducer, preloadedState) => {泛型类型参数的泛型函数,这就是编译器报告两个S类型之间不兼容的原因。

我建议的解决方案是S不是通用的,我可以告诉reducer和有效负载应该具有与StoreEnhancerStoreCreator相同的泛型类型参数。此解决方案需要在ConfigStoreEnhancerStoreCreator中添加额外的类型参数:

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; } 被宣布(间接地,通过storage)返回StoreEnhancer,这是一个必须适用于所有StoreEnhancerStoreCreator的通用函数。然而,给S的一个特定的召唤产生了一个商店创建者只适用于一个storageSS通过。

在我看来,你可以生成config的唯一方法是,如果你开始使用StoreEnhancerStoreCreator函数本身在serialize中是通用的。我不确定这在你的场景中是否有意义。也许熟悉Redux的人会更好地了解该怎么做。

另一答案

S让我走上正轨:

此解决方案需要在Titian Cernicova-Dragomir's answerStoreEnhancerStoreCreator中添加额外的类型参数

但是,适当的类型参数已经存在;我只是不明白如何正确使用它。具体来说,StoreEnhancer返回带有默认类型参数的StoreEnhancer。如果我改为设置类型参数,我现在知道将返回什么样的状态:

StoreEnhancerStoreCreator

以上是关于如何关联高阶函数之间定义的泛型类型?的主要内容,如果未能解决你的问题,请参考以下文章

trait 的泛型类型和泛型关联类型之间有啥区别?

如何调用具有泛型类型的结构的关联函数?

选择Typescript的原因:支持定义执行时的泛型参数

java泛型中的下限

当类的泛型相关时,如何在两个泛型类之间创建类似子类型的关系呢

如何将方法的泛型类型限制为打字稿中的对象?