Search code examples
typescriptundefinedtype-coercion

TypeScript undefined coercing


I was writing a Redux reducer when I found that this code:

export function users(state: { myself: IUser | undefined, users: IUser[] } = { myself: undefined, users: [] }, action: UserActions) {
  const mself = state.myself;
  if (action.type === EMyselfAction.CHANGE_MYSELF_CONFIG && state.myself !== undefined) {
    return {
      myself: myself(mself, action),
      users: state.users.map((u) => user(u, action, state.myself.id)),
    };
  }
  ...
}

Is outputting the error Object is possibly 'undefined':

enter image description here

How can be state.myself undefined if it is already checked that it is not?


Solution

  • I think that's because state.myself is in a different scope.

    export function users(state: { myself: IUser | undefined, users: IUser[] } = { myself: undefined, users: [] }, action: UserActions) {
      const mself = state.myself;
      if (action.type === EMyselfAction.CHANGE_MYSELF_CONFIG && state.myself !== undefined) {
        state.myself // (property) myself: IUser
    
        const foo = () => {
           state.myself // but here is (property) myself: IUser | undefined
        }
        // ...
      }
      ...
    }
    

    I don't think you can guarantee otherwise, since you can use it somewhere else (not only in that branch where state.myself !== undefined). So you could do this:

    export function users(state: { myself: IUser | undefined, users: IUser[] } = { myself: undefined, users: [] }, action: UserActions) {
      const mself = state.myself;
      if (action.type === EMyselfAction.CHANGE_MYSELF_CONFIG && state.myself !== undefined) {
        const id = state.myself.id;
        return {
          myself: myself(mself, action),
          users: state.users.map((u) => user(u, action, id)),
        };
      }
      ...
    }