Switch for specific type in TypeScript
You'd be better off using an if
statement with typeguards.
let action: Action = ...;
if (isSpecificAction(action)) {
console.log(action.payload);
}
function isSpecificAction(action: any): action is SpecificAction {
return action.payload;
}
At the end of the day, TypeScript is still JavaScripty, and the switch
statement gets transpiled to a regular JS switch
:
A switch statement first evaluates its expression. It then looks for the first case clause whose expression evaluates to the same value as the result of the input expression (using the strict comparison, ===)
So in your case:
interface Action {}
class SpecificAction implements Action {
payload?: any
}
let action: Action
switch (action) {
case SpecificAction: //it works
console.log(action.payload) // it doesn't
}
action
would be evaluated and compared with the class SpecificAction
. Presumably, action
is an instance of SpecificAction
(or some object that implements the Action
interface).
With a switch
, you could do this:
let a: Action = new SpecificAction();
let b: Action = a;
switch (a) {
case b:
console.log("Worked");
}
The expression a
is evaluated and compared to the expression b
(and a === b
, so we hit the console.log
), but that's obviously not what you're looking for.
If you want to check if an instance is of a particular type (re: class), then you should use a type guard. A switch/case
is the wrong construct.
Alternatively, why not use instanceof
?
interface Action { };
class SpecificAction implements Action {}
class NotSpecificAction implements Action {}
let action: Action = new SpecificAction();
console.log(action instanceof SpecificAction); // true
console.log(action instanceof NotSpecificAction); // false
for the time being it looks like there are a few options, all of them with some drawbacks
- discriminated unions docs stackblitz, but you'll need a dedicated property as discriminator
interface Action {}
class SpecificAction implements Action {
kind: "specific";
payload?: any;
}
class ToggleAction implements Action {
kind: "toggle";
toggle: boolean;
}
let action: SpecificAction | ToggleAction;
switch (action.kind) {
case "specific":
console.log(action.payload) // it works
break;
case "toggle":
console.log(action.toggle) // it works
break;
}
- User-Defined Type Guards docs stackblitz, but you'll need if statements instead of switch
interface Action {}
class SpecificAction implements Action {
payload?: any;
}
class ToggleAction implements Action {
toggle: boolean;
}
let isSpecific = (p: any): p is SpecificAction => !!p.payload
let isToggle = (p: any): p is ToggleAction => !!p.toggle
let action: Action;
if (isSpecific(action)) {
console.log(action.payload) // it works
} else if (isToggle(action)) {
console.log(action.toggle) // it works
}
- constructor property github stackblitz, but you'll need to cast to desired type for the time being
interface Action { }
class SpecificAction implements Action {
payload?: any;
}
class ToggleAction implements Action {
toggle: boolean;
}
switch (action.constructor) {
case SpecificAction:
console.log((<SpecificAction>action).payload) // it kinda works
break;
case ToggleAction:
console.log((<ToggleAction>action).toggle) // it kinda works
break;
}