Typescript enum switch not working - enums

i have the following enum
enum EditMode {
View = 0,
Edit = 1,
Delete = 2
}
Let's assume i have a variable of the enum type
var editMode = EditMode.Edit;
Why does the following code not work (goes straight to default)?
switch (editMode) {
case EditMode.Delete:
...
break;
case EditMode.Edit:
...
break;
default:
...
break;
}

I also had this problem. Easy way to get around it: add a + sign before your variable in the switch, i.e.
switch (+editMode) {
case EditMode.Delete:
...
break;
case EditMode.Edit:
...
break;
default:
...
break;
}

i have found why i does happen. somewhere in the code there is a activation function (i am using durandal) which passes this enum as a string (the function has the parameter marked as a enum but still it is a string). this is why my switch statement fails. i simply converted the value to a number and now everything works as expected. thanks anyways

The issue here has to do with typescript's (numeric) literal types. When you do this assignment:
var editMode = EditMode.Edit
TypeScript evaluates the type as:
var editMode: 1 = EditMode.Edit
Now, when you compare a value that typescript knows must be 1 (EditMode.Edit) to a value that it knows must be 0 (EditMode.View), it sees all this as a type-safety violation. If the variable editMode weren't an enum, typescript would merely complain, but since it's an enum, which doesn't really exist in javascript, typescript gets to control the transpilation in such a way that it actually throws an error.
So you have 2 options. So you can either coerce editMode to be a number or to be an EditMode (i.e. any of the values EditMode is permitted to be, not just the one assigned to editMode the variable).
Personally, I prefer to coerce it to be an EditMode, because it feels more type-safe.
To go the number route, you can do the following, which was previously mentioned:
switch(+editMode)
To go the EditMode route (which I recommend), you can pass it to a function as was mentioned, but sometimes it's a little cleaner to not write a function. If that's the case here, then you can again coerce the type in the switch statement:
switch(editMode as EditMode)
Do whichever you prefer, but I just like the clarity of explicitly saying "this variable is being treated as an EditMode" as opposed to "this variable is supposed to actually be a number, not an Enum".

TypeScript version 3.7.5
this code worked for me
enum Seasons {
Winter,
Spring,
Summer,
Autum
}
switch (+Seasons.Winter) {
case Seasons.Winter:
console.log('weather is cold');
break;
case Seasons.Spring:
console.log('weather is spring');
break;
case Seasons.Summer:
console.log('weather is summer');
break;
default:
break;
}
or you can declare a constant and use as param for switch statement
const season: Seasons = Seasons.Winter
switch (+season) {
case Seasons.Winter:
console.log('weather is cold');
break;
case Seasons.Spring:
console.log('weather is spring');
break;
case Seasons.Summer:
console.log('weather is summer');
break;
default:
break;
}

Change your EditMode enum definition to:
enum EditMode {
View = "View",
Edit = "Edit",
Delete = "Delete"
}
Typescript 3.6.3

In case somebody else ends up here and the above options don't seem to be the issue, double-check that all of your switch statements are breaking/returning! The Typescript compiler is smart enough to see that if your case cascades through to another one, the value you're comparing on may never hit the case you expect.
let handlerName;
switch(method){
case 'create':
handlerName = 'createHandler';
break;
case 'update';
handlerName = 'updateHandler';
// Here is where the forgotten break would go
default:
throw new Error('Unrecognized Method');
}
switch(handlerName){
case 'createHandler':
...
break;
case 'updateHandler':
// You will see an error on this case because
// the compiler knows that execution will never
// arrive here with handler === 'updateHandler'
default:
throw new Error('Unrecognized Handler');
}

With //#ts-ignore suppress you can do:
//#ts-ignore
switch (EditMode[editMode] as EditMode) {
case EditMode.Delete:
...
break;
case EditMode.Edit:
...
break;
default:
...
break;
}
}

If the enum is defined in a separate typescript file, ensure it's marked with "export" and that you import it correctly at the top of the typescript file you're referencing it in.

Use it like this.
const enum OperationsType{
CREATE="CREATE",
DELETE="DELETE",
UPDATE="UPDATE"
}

Int Enum
enum Sizes {
Small,
Medium,
}
switch (Number(Sizes.Small)) {
case Sizes.Small:
// 👇️ this runs
console.log('size is S');
break;
case Sizes.Medium:
console.log('size is M');
break;
default:
console.log(`non-existent size: ${Sizes.Small}`);
break;
}
String Enum
enum Sizes {
Small = 'S',
Medium = 'M',
}
switch (String(Sizes.Small)) {
case Sizes.Small:
console.log('size is S');
break;
case Sizes.Medium:
console.log('size is M');
break;
default:
console.log(`non-existent size: ${Sizes.Small}`);
break;
}

Declare your enum using const:
const enum EditMode {
View = 0,
Edit = 1,
Delete = 2
}

In my case I had the switch inside a condition, which was coercing the enum into a value:
enum A {
VAL_A,
VAL_B,
VAL_C
}
interface ia {
maybe?: A
}
const o: ia = {maybe: 0}
if(o.maybe){ //<-- o.maybe is not falsey (thus, is not 0)
switch(o.maybe) {
case A.VAL_A: //<-- Error! we know that o.maybe is not 0. Its VAL_B | VAL_C
break;
}
}

If you use the switch expression in a function with typed parameter, this works as expected.
Example:
enum EditMode {
View,
Edit,
Delete,
}
function testSwitch(editMode: EditMode) {
switch(editMode) {
case EditMode.Delete:
console.log("delete");
break;
case EditMode.Edit:
console.log("edit");
break;
default:
console.log("default");
break;
}
}
testSwitch(EditMode.Edit)
will compile 🥳 and output edit 👍

Related

Swift: How do I create a sequence of 'if' statements?

I want to know how to write a sequence in an if statement, like I would as a sequence of actions? For example:
If I have var touchedBool = Bool(), how do I create an if statement that says:
if touchedBool == true FOLLOWED BY touchedBool == false THEN
{
// This happens.
}
I believe there should be a better way to accomplish what you really want, but here is the thing I believe you are looking for:
var touchedBool = false {
didSet {
if oldValue && !touchedBool {
print("Boom") // Do your stuff here
}
}
}
var someBool = true
if someBool {
// Do something
} else {
// Do Something
}
For your example, a simple if-else would be fine:
var anyBool: Bool = true
if anyBool == true {
//do something
} else {
//do something else
}
This would work fine for bools, but gets cumbersome for something with multiple options other than true of false. For this, I would recommend a switch statement;
var anyInt = 1
switch anyInt {
case 1:
//do something
case 2:
//do something
case 3:
//do something
case 4:
//do something
default:
//do something else
}
Switch statements are a lot more flexible as well

Enum method call resolves to to "unused function"

I've been messing around in Swift with Xcode Playgrounds. I know that Swift enums are much more powerful than their Obj-C equivalents. So I figured I'd make an enum containing colors as the member values, and add a method to the enum to fetch the hex value of a Color.
However, I get an error-- "Expression resolves to an unused function". I have a feeling that it might have something to do with having the method accept a member value as a parameter, but I'm probably wrong. Code's below. Can somebody enlighten me?
enum Color {
case Red,Blue,Yellow
func hexValue (aColor: Color) -> String { //Find hex value of a Color
switch aColor {
case .Red:
return "#FF0000"
case .Yellow:
return "#FFFF00"
case .Blue:
return "#0000FF"
default:
return "???????"
}
}
}
Color.hexValue(Color.Red) //Error: "Expression resolves to an unused function"
Add static to the declaration of hexValue to create a type method that can be called from the type without an instance:
enum Color {
case Red,Blue,Yellow
static func hexValue (aColor: Color) -> String { //Find hex value of a Color
switch aColor {
case .Red:
return "#FF0000"
case .Yellow:
return "#FFFF00"
case .Blue:
return "#0000FF"
default:
return "???????"
}
}
}
Color.hexValue(Color.Red) // "#FF0000"
Or you could make this nicer by making it a computed property:
enum Color {
case Red,Blue,Yellow
var hexValue: String {
get {
switch self {
case .Red: return "#FF0000"
case .Yellow: return "#FFFF00"
case .Blue: return "#0000FF"
}
}
}
}
Color.Red.hexValue // "#FF0000"
You have to define the hexValue function as static, because you're not calling it from an instance.
Note that the default case is unnecessary, because all possible values are already handled in your switch statement.
However, swift enums are more powerful than that. This is how I would implement it, taking advantage of raw values:
enum Color : String {
case Red = "#FF0000"
case Blue = "#FFFF00"
case Yellow = "#0000FF"
static func hexValue(aColor: Color) -> String {
return aColor.toRaw()
}
}
and obtain the string representation using:
Color.hexValue(Color.Red)
The hexValue method is redundant though, because you can just use:
Color.Red.toRaw()
Just read the error message!
let color = Color.hexValue(Color.Red)
you have to assign the return value to something
Another option is to use the Printable protocol and implement a description computed property on your Enum, then you can just reference its value using string interpolation.
enum Color: Printable {
case Red,Blue,Yellow
var description: String {
get {
switch self {
case .Red: return "#FF0000"
case .Yellow: return "#FFFF00"
case .Blue: return "#0000FF"
}
}
}
}
let myColor = "\(Color.Red)"

How do I compare an NSNumber to a swift enumeration value?

I'm trying to do a simple comparison of a value received via an NSNotification, and an enumeration value. I have something that works, but I can't believe that this is the right way to be doing this. Basically the solution I ended up with was converting the NSNumber to an Int, and also getting the enum value's rawValue, wrapping it in an NSNumber and then getting the integerValue of that.
Everything else I tried resulted in compiler errors about not being able to convert between Uint 8 and Int or something similar.
observer = NSNotificationCenter.defaultCenter().addObserverForName(AVAudioSessionRouteChangeNotification, object: nil, queue: mainQueue) { notification in
println(AVAudioSessionRouteChangeReason.NewDeviceAvailable.toRaw())
if let reason = notification.userInfo[AVAudioSessionRouteChangeReasonKey!] as? NSNumber {
if (reason.integerValue == NSNumber(unsignedLong:AVAudioSessionRouteChangeReason.NewDeviceAvailable.toRaw()).integerValue) {
self.headphoneJackedIn = true;
} else if (reason.integerValue == NSNumber(unsignedLong:AVAudioSessionRouteChangeReason.OldDeviceUnavailable.toRaw()).integerValue) {
self.headphoneJackedIn = false;
}
self.updateHeadphoneJackLabel()
}
}
This should work:
if reason.integerValue == Int(AVAudioSessionRouteChangeReason.NewDeviceAvailable.rawValue) {
// ...
}
Remark: The AVAudioSessionRouteChangeReason enumeration uses UInt as raw value type, so
one could expect that this works without an explicit conversion:
if reason.unsignedIntegerValue == AVAudioSessionRouteChangeReason.NewDeviceAvailable.rawValue {
}
However, as of Xcode 6 beta 4, NSUInteger is mapped to Swift's Int in OS X and iOS
system frameworks, which means that both integerValue and unsignedIntegerValue return an Int,
and an explicit conversion is needed in any case.
Alternatively, you could create an enumeration value from the number (as already suggested by #ColinE
in a comment) and then use switch case:
if let r = AVAudioSessionRouteChangeReason(rawValue: UInt(reason.integerValue)) {
switch r {
case .NewDeviceAvailable:
// ...
case .OldDeviceUnavailable:
// ...
default:
// ...
}
} else {
println ("Other reason")
}
For the same reason as above, an explicit UInt conversion is necessary here as well.

Xcode 6 runtime attributes with Swift enums

I have a class in Swift called Button:
enum ButtonBackgroundColor {
case None
case Yellow
}
class Button: UIButton {
var backgroundColorType: ButtonBackgroundColor?
}
And then I'm setting a runtime attribute:
However, I get a non-descriptive crash. The stack trace mentions something about key value coding.
Runtime attributes do work however for non enum types, like Int or Float:
// runtime attributes work for this
var backgroundColorType: Int = 0
Is there something wrong with the way I'm declaring my enum?
Given that your enum ButtonBackgroundColor includes a .None case, why not avoid declaring backgroundColorType in Button as an optional? Doing so needlessly complicates the declaration. Prefer
class Button: UIButton {
var backgroundColorType = ButtonBackgroundColor.None
}
Besides being more idiomatically correct, the above might, just might, fix your 'user defined attribute' issue now that the variable is not an optional.
You also might need to provide raw values in your enum. Like:
enum ButtonBackgroundColor : Int {
case None = 0
case Yellow = 1
}
if you expect the runtime attribute value of '0' to perhaps map to .None
#GoZoner's answer didn't work for me. Tried changing the raw type to String and that didn't work as well. My solution is to define another variable (of whichever type supported by the runtime attributes) and then override the didSet of that variable to set the enum.
So in code:
var IBButtonBackgroundColor = "None"
{
didSet
{
switch self.IBButtonBackgroundColor
{
case "None":
self.backgroundColorType = .None
break
case "Yellow":
self.backgroundColorType = .Yellow
break
default:
self.backgroundColorType = .None
break
}
}
}
var backgroundColorType:ButtonBackgroundColor = .None
I don't like having to repeat things in the switch/case, but I can't think of any better solution for now.

Why does a switch statement on a string fail when the value comes from ViewBag?

I have the following code in a CSHTML razor page:
#{
var sort = ViewBag.Sort.ToString();
switch (sort)
{
case "None": Html.Action("SortNone"); break;
case "Name": Html.Action("SortName"); break;
case "Date": Html.Action("SortDate"); break;
}
}
However, this is failing with a Compiler Error Message:
CS0151: A switch expression or case label must be a bool, char, string, integral, enum, or corresponding nullable type
But sort is a string! Rewriting this as a series of if/else statements works, but is not as elegant.
Try casting, the compiler doesn't know the return type of ToString() because it is dynamic.
var sort = (string)ViewBag.Sort.ToString();

Resources