reactjs - 类型 'loginToken' 上不存在属性 '{ loginToken: string; } | { error: Error; } | { username: string; password: string; }'

标签 reactjs typescript redux redux-saga

我正在尝试使用 typescript/redux 创建一个 reducer ,但遇到了这个错误

Property 'loginToken' does not exist on type '{ loginToken: string; } | { error: Error; } | { username: string; password: string; }'.
  Property 'loginToken' does not exist on type '{ error: Error; }'

我的 reducer 如下:

export default (state = userState, action: UsersActions) => {
  switch (action.type) {
    case ActionTypes.USER_LOGIN_REQUEST:
      return {
        ...state,
        isAuthenticated: false,
        isLoading: true,
      };
    case ActionTypes.USER_LOGIN_SUCCESS:
      return {
        ...state,
        isAuthenticated: true,
        loginToken: action.payload.loginToken,
        isLoading: false,
      };

我的操作类型:

export interface UserLoginRequest extends Action {
  type: typeof ActionTypes.USER_LOGIN_REQUEST; // !! here we assign the string literal type of the constant
  payload: {
    username: string;
    password: string;
  };
}

export interface UserLoginSuccess extends Action {
  type: typeof ActionTypes.USER_LOGIN_SUCCESS; // !! here we assign the string literal type of the constant
  payload: {
    loginToken: string;
  };
}

export interface UserLoginFailure extends Action {
  type: typeof ActionTypes.USER_LOGIN_FAILURE; // !! here we assign the string literal type of the constant
  payload: {
    error: Error;
  };
}

export interface User {
  username: string;
  password: string;
  loginToken: string;
  loginError?: Error;
  status?: number;
}

export type UsersActions = 
| UserLoginSuccess
| UserLoginFailure
| UserLoginRequest;

Action 类型是一个像这样的枚举:

enum ActionTypes {
    USER_LOGIN_REQUEST = 'request',
    USER_LOGIN_SUCCESS = 'success',
    USER_LOGIN_FAILURE = 'failure',
};

也许我没有得到有关 Typescript 的信息,这就是为什么?如果可以提供任何资源或见解,我们将不胜感激。

最佳答案

问题是 UsersActions 可以是以下三者之一 - UserLoginSuccess、UserLoginFailure 或 UserLoginRequest - 它是联合类型。

在“成功”的情况下,知道登录 token 将存在,并且类型是 UserLoginSuccess - 但 TypeScript 没有任何方式知道这一点,所以它告诉您您可能正在尝试从(例如)UserLoginFailure 类型获取 loginToken 属性。

解决方案是you've got to narrow the type when you want to work with it 。由于联合类型上没有可以打开的通用属性,因此我认为执行此操作的唯一方法是将有效负载转换为正确的类型:

case ActionTypes.USER_LOGIN_SUCCESS:
  return {
    ...state,
    isAuthenticated: true,
    loginToken: (action.payload as UserLoginSuccess).loginToken,
    isLoading: false,
  };

编辑

抱歉,我刚刚重新阅读了您的问题,发现有一个更好的解决方案 - 当您创建联合类型时,您使用 typeof 作为操作类型 -

export interface UserLoginRequest extends Action {
  type: typeof ActionTypes.USER_LOGIN_REQUEST;
  // ...
}

所以 type 将是该属性的类型 - 但我猜你真正想要做的是使其成为已知值?

我不知道 ActionsTypes 的定义是什么,但如果这是一个 enum -

enum ActionTypes {
    USER_LOGIN_REQUEST = 'request',
    USER_LOGIN_SUCCESS = 'success',
    USER_LOGIN_FAILURE = 'failure',
};

然后您可以更改类型定义以使用枚举类型 -

interface UserLoginRequest extends Action {
  type: ActionTypes.USER_LOGIN_REQUEST;
  payload: {
    username: string;
    password: string;
  };
}

现在,当您打开类型时,TS 会正确地为您缩小有效负载 -

switch (action.type) {
    case ActionTypes.USER_LOGIN_SUCCESS:
        console.log(action.payload.loginToken); // TS is happy!
        break;

    default:
        console.log('NOT A SUCCESS ACTION');
}

Here's a quick repro in TS playground

关于reactjs - 类型 'loginToken' 上不存在属性 '{ loginToken: string; } | { error: Error; } | { username: string; password: string; }',我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67695950/

相关文章:

javascript - 具有多个 react 根节点的 Redux

react-native - 如何在 React Native 中编写和建模可重用的业务逻辑

javascript - 在 React 中使用 map 函数时出错

reactjs - Jest 在尝试导入组件时抛出错误 Unexpected token function

javascript - 注销后使用 React with Meteor : how to handle Meteor. user()

React float-left 中的 Html 不起作用

typescript - 将字符串转换为 typescript 枚举的通用函数

javascript - 如何在 Typescript 界面中强制使用分号

jquery - 为 jquery 扩展编写 typescript 类型定义

javascript - webpack 中的无效配置对象