typescript - Redux 4.0 中存储增强器的 TypeScript 输入问题

标签 typescript redux

一些 TypeScript 大师能帮我弄清楚为什么在 redux 4.0 中创建存储增强器的代码会给我类型错误吗?

最小 repo 是 here .它正在创建一个无所事事的商店 ehnahcer。克隆后,通过运行 yarn 安装依赖项.要查看错误,请运行 yarn run compile .

相关文件是

import {
  StoreEnhancer,
  StoreEnhancerStoreCreator,
  Reducer,
  DeepPartial,
  AnyAction,
} from 'redux';

interface RootState {
  someKey: string;
}

export const enhancer: StoreEnhancer =
  (createStore: StoreEnhancerStoreCreator): StoreEnhancerStoreCreator =>
    (reducer: Reducer<RootState, AnyAction>, preloadedState?: DeepPartial<RootState>) => {

  const store = createStore(reducer, preloadedState);
  const newDispatch: typeof store.dispatch = <A extends AnyAction>(action: A) => {
    const result = store.dispatch(action);
    return result;
  }
  return {
    ...store,
    dispatch: newDispatch,
  };
};


我得到的错误是

src/enhancer.ts(15,5): error TS2322: Type '(reducer: Reducer<RootState, AnyAction>, preloadedState?: DeepPartial<RootState> | undefined) => ...' is not assignable to type 'StoreEnhancerStoreCreator<{}, {}>'.
  Types of parameters 'reducer' and 'reducer' are incompatible.
    Types of parameters 'state' and 'state' are incompatible.
      Type 'RootState | undefined' is not assignable to type 'S | undefined'.
        Type 'RootState' is not assignable to type 'S | undefined'.
          Type 'RootState' is not assignable to type 'S'.

我不明白为什么RootState不能分配给 S .

最佳答案

让我们深入了解 StoreEnhancerStoreCreator被定义为

export type StoreEnhancerStoreCreator<Ext = {}, StateExt = {}> = <S = any, A extends Action = AnyAction>(reducer: Reducer<S, A>, preloadedState?: DeepPartial<S>) => Store<S & StateExt, A> & Ext;
这是具有两个类型参数的泛型类型,ExtStateExt .这种类型的结果是另一个泛型函数。例如,如果我们这样做
const genericStoreCreator: StoreEnhancerStoreCreator = <S = any, A extends Action = AnyAction>(r: Reducer<S, A>) => createStore(r)
genericStoreCreator仍将是通用功能。我们已经使用了泛型 StoreEnhancerStoreCreator没有向它提供类型参数(具有默认类型值),但结果仍然是通用函数。
那么我们可以调用genericStoreCreatorS 提供特定类型参数和 A .
const store = genericStoreCreator((state: RootState = { someKey: 'someKey' }, action: AnyAction) => state)
现在我们有具体的store没有任何泛型。
您可以考虑StoreEnhancerStoreCreator作为泛型内部的泛型。
现在让我们回到存储增强器。来自 source (在文档中没有找到)

A store enhancer is a higher-order function that composes a store creator to return a new, enhanced store creator.


所以商店增强器的结果应该仍然是通用商店创建者。在增强器函数内部,我们不应该与特定的状态形状(即它具有 someKey 属性)或特定的 Action 形状(除非它具有 type 属性)相关联。在实现增强器时,我们不知道它将增强哪个确切的商店。
为了使您的代码正常工作,只需在增强器代码中携带泛型
export const enhancer: StoreEnhancer =
  (createStore: StoreEnhancerStoreCreator): StoreEnhancerStoreCreator =>
    <S = any, A extends Action = AnyAction>(reducer: Reducer<S, A>, preloadedState?: DeepPartial<RootState>) => {

  const store = createStore(reducer, preloadedState);
  const newDispatch: Dispatch<A> = (action) => {
    const result = store.dispatch(action);
    return result;
  }
  return {
    ...store,
    dispatch: newDispatch,
   };
};
请注意,增强型商店创建者仍然是通用的,并且可以是具有任何状态和操作的用户。
但是我们可以用增强剂增强什么?如source says

@template Ext Store extension that is mixed into the Store type.

@template StateExt State extension that is mixed into the state type.


让我们用 print5 扩展存储调用时会将 5 记录到控制台的函数。
export const enhancer: StoreEnhancer<{ print5: () => void }> =
  (createStore: StoreEnhancerStoreCreator): StoreEnhancerStoreCreator<{ print5: () => void }> =>
    <S = any, A extends Action = AnyAction>(reducer: Reducer<S, A>, preloadedState?: DeepPartial<RootState>) => {

  const store = createStore(reducer, preloadedState);
  const newDispatch: Dispatch<A> = (action) => {
    const result = store.dispatch(action);
    return result;
  }
  return {
    ...store,
    dispatch: newDispatch,
    print5 () { console.log(5) },
   };
  };
再次注意,结果存储仍然是通用的。
这里很简单demo .记下如何print5函数从增强器传播到结果存储。

关于typescript - Redux 4.0 中存储增强器的 TypeScript 输入问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50451854/

相关文章:

javascript - 如何在 ngModel 日期中使用但仅使用月、年和日期

javascript - 导出时输入 "only refers to a type, but is being used as a value here"

redux - Redux Toolkit 中的不变性检查中间件有什么作用?

reactjs - 使用 redux 中间件控制 react 路由器导航

javascript - Jest 显示访问 PropTypes 和 createClass 的 console.warn

javascript - Angular2 中两个组件干扰文件事件

css - 在 redux 中添加动画

javascript - 拆分 Reducer 时出错

typescript - 为什么在 TypeScript 中禁止实现具有非公共(public)成员的类?

vue.js - 如何在大型 SPA 中使用良好的 VueX 商店设计?