You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Using switch on discriminated unions with an unrecognized discriminant #13467
class ActionTypes {
public static readonly TypeA = "TypeA";
public static readonly TypeB = "TypeB";
}
interface Action {
type: string;
payload?: any;
}
class ActionA implements Action {
public readonly type = ActionTypes.TypeA;
constructor(public payload: {}) { }
}
class ActionB implements Action {
public readonly type = ActionTypes.TypeB;
}
declare type Actions = ActionA | ActionB;
let otherType = "something-else";
function test(action: Actions | Action) {
switch (action.type) {
case otherType:
console.log("Something Else");
break;
case ActionTypes.TypeB:
console.log("ActionB");
break;
case ActionTypes.TypeA:
console.log("ActionA", action.payload);
break;
}
}
Expected behaviour:
The last switch statement should narrow to TypeA. It doesn't when the input parameter is of type "Actions | Action" or the otherType switch statement is there.
Actual behaviour:
Property 'payload' does not exist on type Action | ActionA | ActionB. Property payload does not exist on type ActionB.
Jinder Sidhu (@jinder) The reason is basically that if we say that a type T represents either any stringor respresents some specific stringS we are saying that T represents any string since the specific stringS is a string that can be represented by T. This makes the union "collapse". Does this sound right?
Activity
aluanhaddad commentedon Jan 14, 2017
This is expected.
is equivalent to
The
type: stringin the interface subsumes the rest of the union, making it impossible for the type guards to narrow from it.Consider using this pattern instead
jinder commentedon Jan 14, 2017
Aluan Haddad (@aluanhaddad) I see, thank you. I guess I don't see quite why it would subsume like that.
Closing as this seems to be expected behaviour.
aluanhaddad commentedon Jan 15, 2017
Jinder Sidhu (@jinder) The reason is basically that if we say that a type
Trepresents either anystringor respresents some specificstringSwe are saying thatTrepresents anystringsince the specificstringSis astringthat can be represented byT. This makes the union "collapse". Does this sound right?rkrisztian commentedon Feb 9, 2017
This solution is not good enough for actions in general because we need the
Actioninterface.For example, find-book-page.ts dispatches an action:
this.store.dispatch(new book.SearchAction(query));And book.ts needs to define an
Observable<Action>.I guess casting would be a workaround, but having to do that everytime an
Actionobject is needed, would be cumbersome.