一些 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;
这是具有两个类型参数的泛型类型,Ext
和 StateExt
.这种类型的结果是另一个泛型函数。例如,如果我们这样做const genericStoreCreator: StoreEnhancerStoreCreator = <S = any, A extends Action = AnyAction>(r: Reducer<S, A>) => createStore(r)
genericStoreCreator
仍将是通用功能。我们已经使用了泛型 StoreEnhancerStoreCreator
没有向它提供类型参数(具有默认类型值),但结果仍然是通用函数。那么我们可以调用
genericStoreCreator
为 S
提供特定类型参数和 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/