【问题标题】:Property does not exist on type error with Union Types in Typescript Reac + ReduxTypescript React + Redux 中的 Union Types 类型错误时属性不存在
【发布时间】:2018-11-20 14:37:00
【问题描述】:

我是 React 和 Redux 的新手,我正在使用 Typescript 制作一个小项目。我创建了我的第一个 reducer 和操作,但我遇到了一个问题:每当我尝试访问有效负载的内容时,我都会得到一个 Type error: property X does not exist in type

动作:

import { Action } from 'redux';
export const LOGIN_ACTION = 'login';
export const LOGIN_SUCCESS_ACTION = 'login-sucesss';
export const LOGIN_FAILED_ACTION = 'login-failed';

export interface LoginAction extends Action {
  type: string;
  payload: {
    username: string;
    password: string;
  };
}

export function login(username: string, password: string): LoginAction {
  return {
    type: LOGIN_ACTION,
    payload: { username, password },
  };
}

export interface LoginSuccessAction extends Action {
  type: string;
  payload: {
    loginToken: string;
  };
}

export function loginSuccess(loginToken: string): LoginSuccessAction {
  return {
    type: LOGIN_SUCCESS_ACTION,
    payload: { loginToken },
  };
}

export interface LoginFailedAction extends Action {
  type: string;
  payload: {
    error: Error;
  };
}

export function loginFailed(error: Error): LoginFailedAction {
  return {
    type: LOGIN_FAILED_ACTION,
    payload: { error },
  };
}

export type LoginActions = LoginAction | LoginSuccessAction | LoginFailedAction;

减速机:

import { LOGIN_ACTION, LOGIN_FAILED_ACTION, LOGIN_SUCCESS_ACTION, LoginActions } from '../../actions/login.action';
import {
  REQ_STATUS_FAIL,
  REQ_STATUS_PROCESSING,
  REQ_STATUS_SUCCESS,
  REQ_STATUS_UNDEFINED,
} from '../../common/request-status';

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

export const initialState: LoginState = {
  username: '',
  password: '',
  loginToken: '',
  loginError: undefined,
  status: REQ_STATUS_UNDEFINED,
};

export function loginReducer(state: LoginState = initialState, action: LoginActions): LoginState {
  switch (action.type) {
    case LOGIN_ACTION:
      console.log('I was here', action.payload);
      return { ...state, username: action.payload.username, password: action.payload.password, status: REQ_STATUS_PROCESSING };

    case LOGIN_SUCCESS_ACTION:
      return { ...state, loginToken: action.payload.loginToken, status: REQ_STATUS_SUCCESS };

    case LOGIN_FAILED_ACTION:
      return { ...state, loginToken: '', loginError: action.payload.error, status: REQ_STATUS_FAIL };

    default:
      return state;
  }
}

问题是我在访问payload的属性时有很多类型错误,比如这里:action.payload.usernameaction.payload.password

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

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

你能帮帮我吗?

【问题讨论】:

    标签: reactjs typescript redux react-redux


    【解决方案1】:

    您正在尝试在 typescript 中使用可区分联合。有区别的联合使用switch 语句,以便根据给定属性(type 在您的情况下)缩小每个分支上的类型。区分联合的要求是 type 属性是文字类型(在您的情况下是字符串文字类型)。由于您为动作类型定义了常量,因此您可以使用typeof constant 来获取为常量推断的字符串文字类型。

    interface Action { } // Dummy for self contained sample
    export const LOGIN_ACTION = 'login';
    export const LOGIN_SUCCESS_ACTION = 'login-sucesss';
    export const LOGIN_FAILED_ACTION = 'login-failed';
    
    export interface LoginAction extends Action {
      type: typeof LOGIN_ACTION; // !! here we assign the string literal type of the constant
      payload: {
        username: string;
        password: string;
      };
    }
    
    export function login(username: string, password: string): LoginAction {
      return {
        type: LOGIN_ACTION,
        payload: { username, password },
      };
    }
    
    export interface LoginSuccessAction extends Action {
      type: typeof LOGIN_SUCCESS_ACTION; // !! here we assign the string literal type of the constant
      payload: {
        loginToken: string;
      };
    }
    
    export function loginSuccess(loginToken: string): LoginSuccessAction {
      return {
        type: LOGIN_SUCCESS_ACTION,
        payload: { loginToken },
      };
    }
    
    export interface LoginFailedAction extends Action {
      type: typeof LOGIN_FAILED_ACTION; // !! here we assign the string literal type of the constant
      payload: {
        error: Error;
      };
    }
    
    export function loginFailed(error: Error): LoginFailedAction {
      return {
        type: LOGIN_FAILED_ACTION,
        payload: { error },
      };
    }
    
    export type LoginActions = LoginAction | LoginSuccessAction | LoginFailedAction;
    
    
    export interface LoginState {
      username: string;
      password: string;
      loginToken: string;
      loginError?: Error;
      status?: number;
    }
    
    export const initialState: LoginState = {
      username: '',
      password: '',
      loginToken: '',
      loginError: undefined,
      status: 0,
    };
    
    export function loginReducer(state: LoginState = initialState, action: LoginActions): LoginState {
      // Type guard fro discriminated union.
      switch (action.type) {
        case LOGIN_ACTION:
          console.log('I was here', action.payload);
          // action is LoginAction here
          return { ...state, username: action.payload.username, password: action.payload.password, status: 0};
    
        case LOGIN_SUCCESS_ACTION:
          // action is LoginSuccessAction here
          return { ...state, loginToken: action.payload.loginToken, status: 1 };
    
        case LOGIN_FAILED_ACTION:
          // action is LoginFailedAction here 
          return { ...state, loginToken: '', loginError: action.payload.error, status: -1 };
    
        default:
          return state;
      }
    }
    

    【讨论】:

    • 感谢您的回答。我想我也可以使用枚举,对吧?
    • 是的,但类似的规则也适用,您必须使用枚举值作为类型来获得缩小类型的开关
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-07-28
    • 1970-01-01
    • 2019-04-09
    • 2021-01-03
    • 2021-10-12
    • 2022-01-04
    • 2016-10-09
    相关资源
    最近更新 更多