場景復現
- 由於使用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>
- 這個mapToDispatchProps就是類似這樣:
{
logout(){
return (dispatch:Dispatch)=>{
sessionStorage.removeItem('access_token');
dispatch(push('/login'))
}
},
}
- 然後將類型提取出來,自己組裝個mapToDispatchProps類型。
let profileDispatchAction={
logout(){
return (dispatch:Dispatch)=>{
sessionStorage.removeItem('access_token');
dispatch(push('/login'))
}
}
}
type mapToDispatchPropsFunction<T> ={
[K in keyof T]:()=>void|{type:string,payload:any}
}
type mapToDispatchProps=mapToDispatchPropsFunction<typeof profileDispatchAction>
- 最後把所有類型結合一下:
type Props = PropsWithChildren<
RouteComponentProps&
ReturnType<typeof mapStateToProps>&
mapToDispatchProps
>
- 就完美啦。