有些TypeScript主人可以帮我弄清楚为什么在redux 4.0中创建商店增强器的代码给我类型错误?
最小回购是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
。
答案 0 :(得分:2)
深入探讨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
仍然是 generic 函数。我们已经使用了通用类型StoreEnhancerStoreCreator
,而没有为其提供类型参数(具有默认类型值),但是结果仍然是通用函数。
然后我们可以调用genericStoreCreator
,为S
和A
提供特定的类型参数。
const store = genericStoreCreator((state: RootState = { someKey: 'someKey' }, action: AnyAction) => state)
现在我们有了没有任何泛型的特定store
。
您可以将StoreEnhancerStoreCreator
视为泛型。
现在让我们回到存储增强器。来自source(在文档中找不到)
商店增强器是一种高级功能,它构成商店创建者以返回新的增强型商店创建者。
因此,商店增强器的结果仍然应该是通用商店创建者。在增强器函数内部,我们不应该与状态的特定形状(即,具有someKey
属性)或动作的特定形状(除具有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与商店类型混合的商店扩展名。
@template StateExt与状态类型混合的状态扩展。
让我们使用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
函数如何从增强器传播到结果存储。