我正在运行一个使用Redux的Typescript React应用程序。我刚刚从3.7升级到redux的最新版本(截至本文发布时为4.1.2(。我发现redux有一件事很麻烦,那就是连接组件所需的安装代码量,所以我决定为connect编写一个帮助函数。目标是编写一个连接函数,该函数从状态和/或调度中包含一个组件和一组道具。以下是我在更新到4.1.2之前所做的工作:
创建mapStateToProps函数的工厂:
type StoreKey = keyof MyAppState; // MyAppState is a sub-state of the global application state
type AppState<K extends StoreKey = StoreKey> = Pick<MyAppState, K>;
// The 'only' array will be a set of props. For example: ['prop1', 'prop2', 'prop3']
const mapStateToPropsFactory = <K extends StoreKey>(only?: K[]) =>
{
if (!only || only.length === 0)
{
return function (state: GlobalApplicationState): AppState<K>
{
return { ...state.myAppState }
};
}
else
{
return function (state: GlobalApplicationState): AppState<K>
{
let storeKeys = Object.getOwnPropertyNames(state.myAppState) as K[];
return storeKeys.reduce((result, key) =>
{
if (arrayIncludes(only, key))
{
result[key] = state.myAppState[key];
}
return result;
}, {} as AppState<K>);
}
}
}
助手功能:
export function reduxConnectState<P extends AppState<K>, K extends StoreKey>(componentType: React.ComponentType<P>, ...only: K[])
{
return connect(mapStateToPropsFactory<K>(only))(componentType);
}
// Usage:
export default reduxConnectState(MyComponent, "prop1", "prop2", "prop3");
不幸的是,更新后打字中断了。我得到的错误来自helper函数,特别是将componentType传递到connect:的结果中
TS2345: Argument of type 'ComponentType<P>' is not assignable to parameter of type 'ComponentType<Matching<any, P | (ClassAttributes<Component<P, any, any>> & P)>>'.
Type 'ComponentClass<P, any>' is not assignable to type 'ComponentType<Matching<any, P | (ClassAttributes<Component<P, any, any>> & P)>>'.
Type 'ComponentClass<P, any>' is not assignable to type 'ComponentClass<Matching<any, P | (ClassAttributes<Component<P, any, any>> & P)>, any>'.
Types of property 'propTypes' are incompatible.
Type 'WeakValidationMap<P> | undefined' is not assignable to type 'WeakValidationMap<Matching<any, P | (ClassAttributes<Component<P, any, any>> & P)>> | undefined'.
Type 'WeakValidationMap<P>' is not assignable to type 'WeakValidationMap<Matching<any, P | (ClassAttributes<Component<P, any, any>> & P)>> | undefined'.
Type 'WeakValidationMap<P>' is not assignable to type 'WeakValidationMap<Matching<any, P>>'.
Type '(null extends P[K] ? Validator<P[K] | (P[K] & null) | undefined> : undefined extends P[K] ? Validator<P[K] | (P[K] & undefined) | null> : Validator<...>) | undefined' is not assignable to type '(null extends Matching<any, P>[K] ? Validator<Matching<any, P>[K] | (Matching<any, P>[K] & null) | undefined> : undefined extends Matching<...>[K] ? Validator<...> : Validator<...>) | undefined'.
Type 'null extends P[K] ? Validator<P[K] | (P[K] & null) | undefined> : undefined extends P[K] ? Validator<P[K] | (P[K] & undefined) | null> : Validator<...>' is not assignable to type '(null extends Matching<any, P>[K] ? Validator<Matching<any, P>[K] | (Matching<any, P>[K] & null) | undefined> : undefined extends Matching<...>[K] ? Validator<...> : Validator<...>) | undefined'.
Type 'Validator<P[K] | (P[K] & null) | undefined> | (undefined extends P[K] ? Validator<P[K] | (P[K] & undefined) | null> : Validator<P[K]>)' is not assignable to type '(null extends Matching<any, P>[K] ? Validator<Matching<any, P>[K] | (Matching<any, P>[K] & null) | undefined> : undefined extends Matching<...>[K] ? Validator<...> : Validator<...>) | undefined'.
Type 'Validator<P[K] | (P[K] & null) | undefined>' is not assignable to type 'null extends Matching<any, P>[K] ? Validator<Matching<any, P>[K] | (Matching<any, P>[K] & null) | undefined> : undefined extends Matching<...>[K] ? Validator<...> : Validator<...>'.
Type 'null extends P[K] ? Validator<P[K] | (P[K] & null) | undefined> : undefined extends P[K] ? Validator<P[K] | (P[K] & undefined) | null> : Validator<...>' is not assignable to type 'null extends Matching<any, P>[K] ? Validator<Matching<any, P>[K] | (Matching<any, P>[K] & null) | undefined> : undefined extends Matching<...>[K] ? Validator<...> : Validator<...>'.
Type 'Validator<P[K] | (P[K] & null) | undefined> | (undefined extends P[K] ? Validator<P[K] | (P[K] & undefined) | null> : Validator<P[K]>)' is not assignable to type 'null extends Matching<any, P>[K] ? Validator<Matching<any, P>[K] | (Matching<any, P>[K] & null) | undefined> : undefined extends Matching<...>[K] ? Validator<...> : Validator<...>'.
Type 'Validator<P[K] | (P[K] & null) | undefined>' is not assignable to type 'null extends Matching<any, P>[K] ? Validator<Matching<any, P>[K] | (Matching<any, P>[K] & null) | undefined> : undefined extends Matching<...>[K] ? Validator<...> : Validator<...>'.
老实说,我已经查看了redux文件中的新类型,我不知道这里的问题是什么。我尝试了以下实验:
export function reduxConnectState<T extends React.ComponentType<P>, P extends AppState<K>, K extends StoreKey>(componentType: T, ...only: K[])
{
return connect(mapStateToPropsFactory<K>(only))(componentType);
}
但这给我留下了一个不同的错误:
TS2345: Argument of type 'ComponentType<P>' is not assignable to parameter of type 'ComponentType<Matching<ContentEditorState<K> & DispatchProp<AnyAction>, GetProps<T>>>'.
Type 'ComponentClass<P, any>' is not assignable to type 'ComponentType<Matching<ContentEditorState<K> & DispatchProp<AnyAction>, GetProps<T>>>'.
Type 'ComponentClass<P, any>' is not assignable to type 'ComponentClass<Matching<ContentEditorState<K> & DispatchProp<AnyAction>, GetProps<T>>, any>'.
Types of property 'propTypes' are incompatible.
Type 'WeakValidationMap<P> | undefined' is not assignable to type 'WeakValidationMap<Matching<ContentEditorState<K> & DispatchProp<AnyAction>, GetProps<T>>> | undefined'.
Type 'WeakValidationMap<P>' is not assignable to type 'WeakValidationMap<Matching<ContentEditorState<K> & DispatchProp<AnyAction>, GetProps<T>>>'.
Type 'keyof GetProps<T>' is not assignable to type 'keyof P'.
Type 'string' is not assignable to type 'keyof P'.
Type 'string' is not assignable to type 'K'.
'K' could be instantiated with an arbitrary type which could be unrelated to 'string'.
有人能向我解释一下这里发生了什么事吗?谢谢你抽出时间。
这正是我们现在教授使用hooks API作为默认值而不是connect
的原因之一。挂钩API更容易与TS一起使用。
虽然这不是您问题的直接答案,但我强烈建议您重写组件以调用useSelector
而不是connect
。几乎可以肯定的是,这将比试图获得";围绕CCD_ 4包装器的包装器";要正确使用TS:(