Property does not exist on type error with Union Types in Typescript Reac + Redux












1















I am new to React and Redux and I am making a small project using Typescript. I created my first reducer and actions, but I have a problem: whenever I try to access the payload's contents I get a Type error: property X does not exist in type.



Actions:



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;


Reducer:



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;
}
}


The problem is that I have a lot of type errors when accessing the payload's properties, such as here: action.payload.username or action.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; }'.


Could you help me?










share|improve this question



























    1















    I am new to React and Redux and I am making a small project using Typescript. I created my first reducer and actions, but I have a problem: whenever I try to access the payload's contents I get a Type error: property X does not exist in type.



    Actions:



    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;


    Reducer:



    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;
    }
    }


    The problem is that I have a lot of type errors when accessing the payload's properties, such as here: action.payload.username or action.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; }'.


    Could you help me?










    share|improve this question

























      1












      1








      1








      I am new to React and Redux and I am making a small project using Typescript. I created my first reducer and actions, but I have a problem: whenever I try to access the payload's contents I get a Type error: property X does not exist in type.



      Actions:



      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;


      Reducer:



      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;
      }
      }


      The problem is that I have a lot of type errors when accessing the payload's properties, such as here: action.payload.username or action.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; }'.


      Could you help me?










      share|improve this question














      I am new to React and Redux and I am making a small project using Typescript. I created my first reducer and actions, but I have a problem: whenever I try to access the payload's contents I get a Type error: property X does not exist in type.



      Actions:



      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;


      Reducer:



      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;
      }
      }


      The problem is that I have a lot of type errors when accessing the payload's properties, such as here: action.payload.username or action.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; }'.


      Could you help me?







      reactjs typescript redux react-redux






      share|improve this question













      share|improve this question











      share|improve this question




      share|improve this question










      asked Nov 20 '18 at 14:37









      FelipeFelipe

      1,22411731




      1,22411731
























          1 Answer
          1






          active

          oldest

          votes


















          2














          You are trying to use discriminated unions in typescript. Discriminated unions work with switch statements in order to narrow the type on each branch according to a given property (type in your case). A requirement of discriminated unions is for the type property to be a literal type (in your case a string literal type). Since you define constants for the type of the action you can use typeof constant to get the string literal type inferred for the 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;
          }
          }





          share|improve this answer
























          • Thanks for the answer. I suppose that I could also use an Enum, right?

            – Felipe
            Nov 20 '18 at 15:40











          • Yes but similar rules apply, you would have to use a value of enum as a type to get the switch to narrow the type

            – Titian Cernicova-Dragomir
            Nov 20 '18 at 15:43











          Your Answer






          StackExchange.ifUsing("editor", function () {
          StackExchange.using("externalEditor", function () {
          StackExchange.using("snippets", function () {
          StackExchange.snippets.init();
          });
          });
          }, "code-snippets");

          StackExchange.ready(function() {
          var channelOptions = {
          tags: "".split(" "),
          id: "1"
          };
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function() {
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled) {
          StackExchange.using("snippets", function() {
          createEditor();
          });
          }
          else {
          createEditor();
          }
          });

          function createEditor() {
          StackExchange.prepareEditor({
          heartbeatType: 'answer',
          autoActivateHeartbeat: false,
          convertImagesToLinks: true,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: 10,
          bindNavPrevention: true,
          postfix: "",
          imageUploader: {
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          },
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          });


          }
          });














          draft saved

          draft discarded


















          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53395372%2fproperty-does-not-exist-on-type-error-with-union-types-in-typescript-reac-redu%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown

























          1 Answer
          1






          active

          oldest

          votes








          1 Answer
          1






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes









          2














          You are trying to use discriminated unions in typescript. Discriminated unions work with switch statements in order to narrow the type on each branch according to a given property (type in your case). A requirement of discriminated unions is for the type property to be a literal type (in your case a string literal type). Since you define constants for the type of the action you can use typeof constant to get the string literal type inferred for the 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;
          }
          }





          share|improve this answer
























          • Thanks for the answer. I suppose that I could also use an Enum, right?

            – Felipe
            Nov 20 '18 at 15:40











          • Yes but similar rules apply, you would have to use a value of enum as a type to get the switch to narrow the type

            – Titian Cernicova-Dragomir
            Nov 20 '18 at 15:43
















          2














          You are trying to use discriminated unions in typescript. Discriminated unions work with switch statements in order to narrow the type on each branch according to a given property (type in your case). A requirement of discriminated unions is for the type property to be a literal type (in your case a string literal type). Since you define constants for the type of the action you can use typeof constant to get the string literal type inferred for the 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;
          }
          }





          share|improve this answer
























          • Thanks for the answer. I suppose that I could also use an Enum, right?

            – Felipe
            Nov 20 '18 at 15:40











          • Yes but similar rules apply, you would have to use a value of enum as a type to get the switch to narrow the type

            – Titian Cernicova-Dragomir
            Nov 20 '18 at 15:43














          2












          2








          2







          You are trying to use discriminated unions in typescript. Discriminated unions work with switch statements in order to narrow the type on each branch according to a given property (type in your case). A requirement of discriminated unions is for the type property to be a literal type (in your case a string literal type). Since you define constants for the type of the action you can use typeof constant to get the string literal type inferred for the 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;
          }
          }





          share|improve this answer













          You are trying to use discriminated unions in typescript. Discriminated unions work with switch statements in order to narrow the type on each branch according to a given property (type in your case). A requirement of discriminated unions is for the type property to be a literal type (in your case a string literal type). Since you define constants for the type of the action you can use typeof constant to get the string literal type inferred for the 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;
          }
          }






          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered Nov 20 '18 at 14:45









          Titian Cernicova-DragomirTitian Cernicova-Dragomir

          66.1k34361




          66.1k34361













          • Thanks for the answer. I suppose that I could also use an Enum, right?

            – Felipe
            Nov 20 '18 at 15:40











          • Yes but similar rules apply, you would have to use a value of enum as a type to get the switch to narrow the type

            – Titian Cernicova-Dragomir
            Nov 20 '18 at 15:43



















          • Thanks for the answer. I suppose that I could also use an Enum, right?

            – Felipe
            Nov 20 '18 at 15:40











          • Yes but similar rules apply, you would have to use a value of enum as a type to get the switch to narrow the type

            – Titian Cernicova-Dragomir
            Nov 20 '18 at 15:43

















          Thanks for the answer. I suppose that I could also use an Enum, right?

          – Felipe
          Nov 20 '18 at 15:40





          Thanks for the answer. I suppose that I could also use an Enum, right?

          – Felipe
          Nov 20 '18 at 15:40













          Yes but similar rules apply, you would have to use a value of enum as a type to get the switch to narrow the type

          – Titian Cernicova-Dragomir
          Nov 20 '18 at 15:43





          Yes but similar rules apply, you would have to use a value of enum as a type to get the switch to narrow the type

          – Titian Cernicova-Dragomir
          Nov 20 '18 at 15:43




















          draft saved

          draft discarded




















































          Thanks for contributing an answer to Stack Overflow!


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          To learn more, see our tips on writing great answers.




          draft saved


          draft discarded














          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53395372%2fproperty-does-not-exist-on-type-error-with-union-types-in-typescript-reac-redu%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown





















































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown

































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown







          Popular posts from this blog

          Biblatex bibliography style without URLs when DOI exists (in Overleaf with Zotero bibliography)

          ComboBox Display Member on multiple fields

          Is it possible to collect Nectar points via Trainline?