I have 2 enums Color and Shape.
The SHAPES_BY_COLOR constant maps the available shapes to the individual colors.
Later, I want to perform different actions based on the selected color and shape by using a simple switch/case statement.
Is there a way that TypeScript "tells me" that a shape is missing or not available for the current color?
enum Color {
blue = "blue",
green = "green",
red = "red",
orange = "orange"
}
enum Shape {
star = "star",
rectangle = "rectangle",
ellipse = "ellipse",
triangle = "triangle",
diamond = "diamond",
}
const SHAPES_BY_COLOR: Record<Color, Shape[]> = {
[Color.blue]: [
Shape.triangle,
Shape.diamond,
],
[Color.green]: [
Shape.star,
Shape.triangle,
Shape.diamond,
],
[Color.red]: [
Shape.ellipse,
Shape.triangle,
],
[Color.orange]: [
Shape.star,
Shape.triangle,
Shape.diamond,
]
}
const getResultForColorBlue = (shape: Shape) => {
// QUESTION: How to ensure that all cases from color "blue" are included here?
// Get a subset of the `Shape` enum from SHAPES_BY_COLOR[Color.Blue]?
switch (shape) {
case Shape.triangle:
return "";
// Show TS error -> Missing shape "Shape.diamond"
case Shape.star: // Show TS error -> Option not available for Color.blue
return "";
}
};
For this case, I use never as a trick. When all your options are exhausted the shape will become never otherwise it will be one of the shape.
enum Color {
blue,
green,
red,
orange
}
enum Shape {
triangle,
star,
diamond,
ellipse
}
const SHAPES_BY_COLOR: Record<Color, Shape[]> = {
[Color.blue]: [
Shape.triangle,
Shape.diamond,
],
[Color.green]: [
Shape.star,
Shape.triangle,
Shape.diamond,
],
[Color.red]: [
Shape.ellipse,
Shape.triangle,
],
[Color.orange]: [
Shape.star,
Shape.triangle,
Shape.diamond,
]
}
const getResultForColorBlue = (shape: Shape) => {
// QUESTION: How to ensure that all cases from color "blue" are included here?
// Get a subset of the `Shape` enum from SHAPES_BY_COLOR[Color.Blue]?
switch (shape) {
case Shape.triangle:
return "";
case Shape.star: // Show TS error -> Option not available for Color.blue
return "";
case Shape.ellipse: // Show TS error -> Option not available for Color.blue
return "";
case Shape.diamond: // Show TS error -> Option not available for Color.blue
return "";
default:
// if any shape is not handled shape won't be never and thus you will get compile time error
const exhaustiveCheck: never = shape
console.log("will trhow type (compile time) error if any category is not handled by switch case")
return ""
}
};
You can do that with ESLint plugin @typescript-eslint/eslint-plugin and using this rule switch-exhaustiveness-check
From your example, you will get this error message
error Switch is not exhaustive. Cases not matched: Shape.rectangle | Shape.ellipse | Shape.diamond @typescript-eslint/switch-exhaustiveness-check
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With