It appears that you are determined to manually list out both the enum
and the interface
, and then rely on TypeScript to alert you if the interface
is missing keys from the enum
(or vice versa).
For instance, suppose you have:
enum Colors { Red = "red", Green = "green", Blue = "blue"};
interface ColorScheme { red: string, green: number, blue: OtherType};
You can utilize conditional types to enable TypeScript to determine if any elements of Colors
are absent from the keys of ColorScheme
:
type MissingKeysFromColorScheme = Exclude<Colors, keyof ColorScheme>;
If there are no missing keys in ColorScheme
, this type should be never
. Otherwise, it will correspond to one of the values of Colors
, such as Colors.Blue
.
You can also instruct the compiler to identify whether ColorScheme
contains any keys that do not align with constituents of Colors
, though this requires a more convoluted process due to limitations when manipulating enum
s programmatically. Here's how you can achieve this:
type ExtraKeysInColorScheme = {
[K in keyof ColorScheme]: Extract<Colors, K> extends never ? K : never
}[keyof ColorScheme];
Similarly, this type should be never
if there are no extra keys. To prompt a compile-time error if either of these is not never
, employ generic constraints along with default type parameters like so:
type ValidateColorScheme<
Missing extends never = MissingKeysFromColorScheme,
Extra extends never = ExtraKeysInColorScheme
> = 0;
Although the type ValidateColorScheme
itself may seem trivial (it evaluates to
0</code), the generic parameters <code>Missing
and
Extra</code provide feedback on errors if their defaults are not <code>never
.
Test it out by implementing:
enum Colors { Red = "red", Green = "green", Blue = "blue" }
interface ColorScheme { red: string, green: number, blue: OtherType }
type VerifyColorScheme<
Missing extends never = MissingKeysFromColorScheme,
Extra extends never = ExtraKeysInColorScheme
> = 0; // no errors
Compare this with:
enum Colors { Red = "red", Green = "green", Blue = "blue" }
interface ColorScheme { red: string, green: number } // Oops, 'blue' is missing
type VerifyColorScheme<
Missing extends never = MissingKeysFromColorScheme, // Error!
Extra extends never = ExtraKeysInColorScheme
> = 0; // The constraint is not satisfied by 'Blue'
And another scenario:
enum Colors { Red = "red", Green = "green", Blue = "blue" }
interface ColorScheme { red: string, green: number, blue: OtherType, indigo: 1} // Oops, 'indigo' is an extra key
type VerifyColorScheme<
Missing extends never = MissingKeysFromColorScheme,
Extra extends never = ExtraKeysInColorScheme // Error!
> = 0; // 'Indigo' does not satisfy the constraint
While these solutions are functional, they are admittedly not elegant.
An alternative approach involves using a dummy class
solely for the purpose of prompting an error if the correct properties are not included:
enum Shapes { Circle = "circle", Square = "square" , Triangle = "triangle"};
class ShapePlan implements Record<Shapes, unknown> {
circle!: string;
square!: number;
triangle!: boolean;
}
interface ShapeBlueprint extends ShapePlan {}
If any properties are omitted, an error will be triggered:
class ShapePlan implements Record<Shapes, unknown> { // Error!
circle!: string;
square!: number;
}
// Class 'ShapePlan' does not correctly implement interface 'Record<Shapes, unknown>'.
// Property 'triangle' is missing in type 'ShapePlan'.
However, this method does not flag extra properties, which may or may not be pertinent in your case.
Hopefully one of these approaches proves useful for your situation. Best of luck!