Advanced Enum Utilities in TypeScript
Enums in TypeScript provide a way to define a set of named constants. However, TypeScript's built-in enum support can be limited for complex scenarios. This challenge asks you to create a set of utility functions to enhance the functionality of enums, enabling more flexible and powerful usage within your TypeScript projects.
Problem Description
You are tasked with creating a module containing utility functions for working with TypeScript enums. These utilities should provide the following functionalities:
values<T extends Enum>: A function that takes an enum typeTas input and returns an array containing all the values of the enum.keys<T extends Enum>: A function that takes an enum typeTas input and returns an array containing all the keys (enum member names) of the enum.valueOf<T extends Enum, K extends keyof T>: A function that takes an enum typeTand a keyKof that enum, and returns the value associated with that key. This should provide type safety, ensuring the key is a valid member of the enum.isIn<T extends Enum, V>: A function that takes an enum typeTand a valueV, and returnstrueifVis a value of the enumT, andfalseotherwise.
An Enum type is defined as a type that is an instance of EnumConstructor. EnumConstructor is a type that represents a constructor function that returns an enum.
Key Requirements:
- The functions must be type-safe, leveraging TypeScript's type system to provide compile-time checks.
- The functions should handle both numeric and string-based enums correctly.
- The functions should be generic, allowing them to work with any enum type.
- The code should be well-documented and easy to understand.
Expected Behavior:
valuesshould return an array of the enum's values in the order they are defined.keysshould return an array of the enum's keys in the order they are defined.valueOfshould return the correct value for a given key. If the key is invalid, it should throw a type error.isInshould correctly identify whether a value is a valid enum value.
Edge Cases to Consider:
- Enums with no members.
- Enums with both numeric and string values.
- Invalid keys passed to
valueOf. - Values that are not enum values passed to
isIn.
Examples
Example 1:
enum Color {
Red = 1,
Green = 2,
Blue = 3,
}
// Using the utilities
const colorValues = values(Color);
const colorKeys = keys(Color);
const redValue = valueOf(Color, Color.Red);
const isInRed = isIn(Color, 1);
const isInYellow = isIn(Color, 4);
// Expected Output:
// colorValues: [1, 2, 3]
// colorKeys: ["Red", "Green", "Blue"]
// redValue: 1
// isInRed: true
// isInYellow: false
Example 2:
enum Status {
Pending = "pending",
Active = "active",
Completed = "completed",
}
// Using the utilities
const statusValues = values(Status);
const statusKeys = keys(Status);
const activeValue = valueOf(Status, Status.Active);
const isInActive = isIn(Status, "active");
const isInInactive = isIn(Status, "inactive");
// Expected Output:
// statusValues: ["pending", "active", "completed"]
// statusKeys: ["Pending", "Active", "Completed"]
// activeValue: "active"
// isInActive: true
// isInInactive: false
Example 3: (Edge Case)
enum EmptyEnum { }
const emptyValues = values(EmptyEnum);
// Expected Output:
// emptyValues: []
Constraints
- The solution must be written in TypeScript.
- The code should be well-formatted and readable.
- The utility functions should be implemented within a single module.
- The solution should not rely on external libraries.
- The
valuesandkeysfunctions should return arrays in the order the enum members are defined.
Notes
- Consider using TypeScript's reflection capabilities (e.g.,
Object.keys,Object.values) to extract enum information. However, be mindful of type safety and potential limitations. - Think about how to handle both numeric and string-based enums in a generic way.
- Pay close attention to type safety when implementing
valueOfandisIn. Use conditional types and type guards to ensure correctness. - The
EnumConstructortype is a helper type to ensure type safety. You don't need to explicitly define it, but it's useful to understand the underlying concept.