2

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?

lilezek
  • 6,976
  • 1
  • 27
  • 45
  • Possible duplicate of [How to suppress TypeScript "error TS2533: Object is possibly 'null' or 'undefined'"?](https://stackoverflow.com/questions/40349987/how-to-suppress-typescript-error-ts2533-object-is-possibly-null-or-undefine) – k0pernikus Aug 26 '17 at 13:44
  • Could you please post the error message as text instead of only posting it as a screenshot? That might help others facing the same errors finding a question via google. – k0pernikus Aug 26 '17 at 13:46
  • TS won't always "change" the type of a parameter due to assertion (`T is` type guards or `!== null` checks). You might have better luck replacing `state.myself` with `mself` and asserting against that (local variable change more readily). – ssube Aug 26 '17 at 14:02
  • @k0pernikus I know how to suppress that error. The problem is that there is a condition which is forcing the `if` body only to be executed if state.myself is not undefined. – lilezek Aug 26 '17 at 14:13
  • @ssube That is one solution but, why is the compiler not asserting the type? It is obvious IMO that state.myself is not undefined due to the assertion. – lilezek Aug 26 '17 at 14:16

1 Answers1

2

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)),
    };
  }
  ...
}
Federkun
  • 36,084
  • 8
  • 78
  • 90