场景复现
- 由于使用redux-thunk,所以action是允许派发函数的。但是写个action函数后做成mapDispatchToProps传给组件后,connect检测类型产生报错,报错如下:
function Profile(props: React.PropsWithChildren<RouteComponentProps<{}, StaticContext, History<HistoryLocationState = History.PoorMansUnknown>.PoorMansUnknown> & ProfileState & {
...;
}>): JSX.Element
类型“(props: PropsWithChildren<RouteComponentProps<{}, StaticContext, PoorMansUnknown> & ProfileState & { validate(): { type: string; payload: Promise<...>; }; logout(): (dispatch: Dispatch<...>) => void; }>) => Element”的参数不能赋给类型“ComponentType<Matching<ProfileState & { validate: () => { type: string; payload: Promise<AxiosResponse<any>>; }; logout: () => void; }, RouteComponentProps<{}, StaticContext, PoorMansUnknown> & ProfileState & { ...; }>>”的参数。
不能将类型“(props: PropsWithChildren<RouteComponentProps<{}, StaticContext, PoorMansUnknown> & ProfileState & { validate(): { type: string; payload: Promise<...>; }; logout(): (dispatch: Dispatch<...>) => void; }>) => Element”分配给类型“FunctionComponent<Matching<ProfileState & { validate: () => { type: string; payload: Promise<AxiosResponse<any>>; }; logout: () => void; }, RouteComponentProps<{}, StaticContext, PoorMansUnknown> & ProfileState & { ...; }>>”。
参数“props”和“props” 的类型不兼容。
不能将类型“PropsWithChildren<Matching<ProfileState & { validate: () => { type: string; payload: Promise<AxiosResponse<any>>; }; logout: () => void; }, RouteComponentProps<{}, StaticContext, PoorMansUnknown> & ProfileState & { ...; }>>”分配给类型“PropsWithChildren<RouteComponentProps<{}, StaticContext, PoorMansUnknown> & ProfileState & { validate(): { type: string; payload: Promise<...>; }; logout(): (dispatch: Dispatch<...>) => void; }>”。
不能将类型“PropsWithChildren<Matching<ProfileState & { validate: () => { type: string; payload: Promise<AxiosResponse<any>>; }; logout: () => void; }, RouteComponentProps<{}, StaticContext, PoorMansUnknown> & ProfileState & { ...; }>>”分配给类型“{ validate(): { type: string; payload: Promise<AxiosResponse<any>>; }; logout(): (dispatch: Dispatch<AnyAction>) => void; }”。
The types returned by 'logout(...)' are incompatible between these types.
不能将类型“void”分配给类型“(dispatch: Dispatch<AnyAction>) => void”。ts(2345)
解决方法
- 最简单方法,直接把props类型改成any。不要用自己组出来的类型。
- 第二种方法,这个报错主要是因为connect函数的声明文件其中对于返回值处理是这么写的:
export type ResolveThunks<TDispatchProps> =
TDispatchProps extends { [key: string]: any }
? {
[C in keyof TDispatchProps]: HandleThunkActionCreator<TDispatchProps[C]>
}
: TDispatchProps;
export type InferThunkActionCreatorType<TActionCreator extends (...args: any[]) => any> =
TActionCreator extends (...args: infer TParams) => (...args: any[]) => infer TReturn
? (...args: TParams) => TReturn
: TActionCreator;
export type HandleThunkActionCreator<TActionCreator> =
TActionCreator extends (...args: any[]) => any
? InferThunkActionCreatorType<TActionCreator>
: TActionCreator;
- 所以可以发现,它多给我们把函数处理掉了,那么我们要么改声明文件,要么自己修改下类型。
- 如果修改声明文件(不建议)那么就把
InferThunkActionCreatorType
那段改成:
export type InferThunkActionCreatorType<TActionCreator extends (...args: any[]) => any> =
TActionCreator extends (...args: infer TParams) => (...args: any[]) => infer TReturn
? (...args: TParams)=>(...args: TParams) => TReturn
: TActionCreator;
-
这样就不会报错了。
-
如果自己修改类型,我们就自己造个dispatchAction类型。本来传入组件使用的类型是:
type Props = PropsWithChildren<RouteComponentProps&ReturnType<typeof mapStateToProps>&typeof mapToDispatchProps>
- 这个mapDispatchToProps就是类似这样:
{
logout(){
return (dispatch:Dispatch)=>{
sessionStorage.removeItem('access_token');
dispatch(push('/login'))
}
},
}
- 然后将类型提取出来,自己组装个mapDispatchToProps类型。
let profileDispatchAction={
logout(){
return (dispatch:Dispatch)=>{
sessionStorage.removeItem('access_token');
dispatch(push('/login'))
}
}
}
type mapDispatchToPropsFunction<T> ={
[K in keyof T]:(...args:any)=>void|{type:string,payload:any}
}
type mapDispatchToProps=mapDispatchToPropsFunction<typeof profileDispatchAction>
- 最后把所有类型结合一下:
type Props = PropsWithChildren<
RouteComponentProps&
ReturnType<typeof mapStateToProps>&
mapDispatchToProps
>
- 就完美啦。