Reactjs 如何在Typescript中为React useReducer钩子操作创建类型定义?
假设我们有如下定义的Reactjs 如何在Typescript中为React useReducer钩子操作创建类型定义?,reactjs,typescript,types,react-hooks,Reactjs,Typescript,Types,React Hooks,假设我们有如下定义的userReducer: 函数userReducer(状态:string,操作:UserAction):string{ 开关(动作类型){ 案例“登录”: 返回action.username; 案例“注销”: 返回“”; 违约: 抛出新错误(“未知的“用户”操作”); } } 定义UserAction类型的最佳方法是什么,这样就可以使用username有效负载和不使用以下内容调用dispatch: dispatch({type:“LOGIN”,username:“Joe”}
userReducer
:
函数userReducer(状态:string,操作:UserAction):string{
开关(动作类型){
案例“登录”:
返回action.username;
案例“注销”:
返回“”;
违约:
抛出新错误(“未知的“用户”操作”);
}
}
定义UserAction
类型的最佳方法是什么,这样就可以使用username
有效负载和不使用以下内容调用dispatch
:
dispatch({type:“LOGIN”,username:“Joe”}});
/* ... */
分派({type:“LOGOUT”});
如果类型定义如下:
键入UserActionWithPayload={
类型:字符串;
用户名:字符串;
};
键入UserActionWithoutPayload={
类型:字符串;
};
导出类型UserAction=UserActionWithPayload | UserActionWithoutPayload;
编译器在“LOGIN”情况下在reducer中引发错误:TS2339:类型“UserAction”上不存在属性“username”。“UserActionWithoutPayload”类型上不存在属性“username”。
如果使用可选成员定义了类型:
导出类型UserAction={
类型:字符串;
用户名?:字符串;
}
然后编译器显示此错误:TS2322:类型“string | undefined”不可分配给类型“string”。类型“未定义”不能分配给类型“字符串”。
这里少了什么?也许整个方法都错了
项目使用TypeScript 3.8.3和React.js 16.13.0
function userReducer(state: string, action: UserAction): any {
switch (action.type) {
case "LOGIN":
return action.username;
case "LOGOUT":
return "";
default:
throw new Error("Unknown 'user' action");
}
}
在此函数中,您将返回类型定义为字符串。但是当您将UserAction作为UserActionWithoutPayload类型传递时,返回值应该是未定义的。这些原因在userReducer(…)函数返回类型和实数返回类型(作为字符串且未定义)之间有所不同。
要解决此问题,您可以将返回类型更改为任意类型
我希望这个答案能对你的工作有所帮助
问候。
林。这种方法看起来不错,问题是你的reducer的返回类型是
string
,但是如果它被传递了UserActionWithoutPayload
,那么它可能返回action.username
,其中username是未定义的
因此,解决这一问题的一种方法是放宽您的回报类型:
function userReducer(state: string, action: UserAction): string | undefined {
switch (action.type) {
case "LOGIN":
return action.username;
case "LOGOUT":
return "";
default:
throw new Error("Unknown 'user' action");
}
}
经过数小时的挖掘和实验,通过Typescript
enum
和操作的联合类型,找到了一个非常优雅的解决方案:
enum UserActionType{
LOGIN=“LOGIN”,
LOGOUT=“注销”
}
类型UserState=string;
类型UserAction=
|{type:UserActionType.LOGIN;用户名:string}
|{type:UserActionType.LOGOUT}
函数userReducer(state:UserState,action:UserAction):字符串{
开关(动作类型){
案例UserActionType.LOGIN:
返回action.username;
案例UserActionType.LOGOUT:
返回“”;
违约:
抛出新错误();
}
}
函数App(){
const[user,userDispatch]=useReducer(userReducer,“”);
函数handleLogin(){
userDispatch({type:UserActionType.LOGIN,用户名:“Joe”});
}
函数handleLogout(){
userDispatch({type:UserActionType.LOGOUT});
}
/* ... */
}
使用上述方法不会出现错误或警告,而且操作使用有一个相当严格的合同。您需要通过类型转换操作为特定的减速器案例提供更多类型信息
键入UserActionWithPayload={
类型:字符串;
用户名:字符串;
};
键入UserActionWithoutPayload={
类型:字符串;
};
输入UserAction=UserActionWithPayload | UserActionWithoutPayload;
函数userReducer(状态:string,操作:UserAction):string{
开关(动作类型){
案例“登录”:
返回(作为UserActionWithPayload的操作)。用户名;
案例“注销”:
返回“”;
违约:
抛出新错误(“未知的“用户”操作”);
}
}
让国家=”;
state=userReducer(state,{type:“LOGIN”,username:“John”});
日志(“登录”,状态);
state=userReducer(state,{type:“LOGOUT”});
日志(“注销”,状态);
请访问此URL进行代码测试。不幸的是,这并没有帮助,因为减速机的实际使用,即:
const[user,userDispatch]=useReducer(userReducer,”)
给出错误:没有重载与此调用匹配。重载1/5’(减速器:减速器无动作,初始化器arg:any,初始化器?:未定义):[any,DispatchWithoutAction]”,出现以下错误。类型为“(state:string,action:UserAction)=>string | undefined”的参数不能分配给类型为“ReducerWithoutAction”的参数。