Skip to content

Instantly share code, notes, and snippets.

@scinscinscin
Created July 20, 2023 13:14
Show Gist options
  • Save scinscinscin/50dea8ae6a23903c2deb7c8a58b86845 to your computer and use it in GitHub Desktop.
Save scinscinscin/50dea8ae6a23903c2deb7c8a58b86845 to your computer and use it in GitHub Desktop.
A utility for building runtime enums which can be validated using Zod
import { ZodEnum, z } from "zod";
interface RuntimeEnumT<T extends Readonly<string[]>> {
// @ts-ignore
validator: ZodEnum<T>;
enums: {
[key in T[number]]: key;
};
}
/**
* A utility for building runtime enums which can be validated using Zod
* Useful for storing enum strings in the database then using them in the frontend
* @param enums An array containing strings to be used for the enum **as const**
* @returns Object with enums and associated validator
* @example ```tsx
* export const publishedEnum = RuntimeEnum(["published", "draft", "under_review"] as const);
* console.log(publishedEnum.enums.draft); // Prints "draft"
*
* // parse throws an error if it does not match
* const validated = publishedEnum.validator.parse("testing");
* console.log(validated); // type: "published" | "draft" | "under_review"
* ```
*/
export function RuntimeEnum<T extends Readonly<string[]>>(enums: T): RuntimeEnumT<T> {
// @ts-ignore
const validator = z.enum(enums);
const enumObject = {} as { [key in T[number]]: key };
enums.forEach((enum_name) => {
enumObject[enum_name as T[number]] = enum_name;
});
// @ts-ignore
return { validator, enums: enumObject };
}
/**
* A utility type for extracting all possible values for a RuntimeEnum
* @example
* ```tsx
* export const statusEnum = RuntimeEnum(["published", "draft", "under_review"] as const);
* type StatusEnum = GetRuntimeEnumValues<typeof statusEnum>;
* = "published" | "draft" | "under_review";
* ```
*/
export type GetRuntimeEnumValues<T> = T extends RuntimeEnumT<infer U> ? U[number] : never;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment