Situation Imagine having an enum with string values like this:
enum Fruit {
Apple = "apple",
Orange = "orange",
Banana = "banana",
Pear = "pear"
}
Users always input a specific string
value ("apple"
, "banana"
, "orange"
, "pear"
) from a drop-down list to ensure valid inputs, which then needs to be converted back to the correct type Fruit
. Here's an example function for that:
function getFruit(fruit: string): Fruit {
switch (fruit) {
case "apple":
return Fruit.Apple
case "banana":
return Fruit.Banana
case "orange":
return Fruit.Orange
case "pear":
return Fruit.Pear
default:
// I'D RATHER AVOID THIS!
return Fruit.Pear
}
}
Challenges
- Maintaining the switch statement can be cumbersome.
- The
getFruit()
function:- accepts any
string
without restricting it to a specific set of values (Typescript won't give a compile error if an invalid value is used). - a default case must be provided along with a default return value.
- accepts any
Inquiry
Is there a more efficient way to achieve the same result? Perhaps using type
/typeof
/keyof
or other methods?
Ideally, I'd like to:
- Avoid using the switch statement entirely - reducing maintenance overhead.
- Restrict the
getFruit()
function to only acceptstring
values that are part of the enum automatically (without manually declaring and maintaining a union of strings).
p.s. Using a different type instead of an enum
is also acceptable as long as the functionality remains intact!
Current Solution Attempt The closest solution achieved so far is:
type Fruits = "apple" | "banana" | "orange" | "pear"
let Fruit = {
Apple = "apple",
Orange = "orange",
Banana = "banana",
Pear = "pear"
}
type Fruit = keyof typeof Fruit
function parseFruit(fruit: Fruits): Fruit {
return Object.keys(Fruit).find((key) => {
return Fruit[key as Fruit] === fruit
}) as Fruit
}
Even with this approach, managing the string literal union type Fruits
and Fruit
is still necessary. This solution would be ideal if there was a way to programmatically create the string literal union type Fruits
.