@@ -76,11 +76,16 @@ This works because a "branded type" creates a distinct type that TypeScript trac
7676of arbitrary strings at compile time, while still allowing unknown values to pass through parsing safely at runtime.
7777
7878` ` ` typescript
79- export const s_unknown_enum_value = z.unknown().brand("unknown enum value")
80- export type UnknownEnumValue = z.infer<typeof s_unknown_enum_value>
79+ export type UnknownEnumStringValue = string & {
80+ _brand: "unknown enum string value"
81+ }
82+
8183
82- export type t_Fruit = "Apple" | "Banana" | "Orange" | UnknownEnumValue
83- export const s_Fruit = z.union([z.enum(["Apple", "Banana", "Orange"]), s_unknown_enum_value])
84+ export type t_Fruit = "Apple" | "Banana" | "Orange" | UnknownEnumStringValue
85+ export const s_Fruit = z.union([
86+ z.enum(["Apple", "Banana", "Orange"]),
87+ z.string().transform((it) => it as typeof it & UnknownEnumStringValue),
88+ ])
8489` ` `
8590
8691This prevents invalid/random values being referenced in the code, whilst also allowing us to make exhaustiveness checks.
@@ -101,7 +106,7 @@ function processFruit(result: t_Fruit): void {
101106 break
102107 default: {
103108 // This checks that we have exhaustively handled the known values
104- const _ = result satisfies UnknownEnumValue
109+ const _ = result satisfies UnknownEnumStringValue
105110 console.warn(` unsupported ${result}, skipping`)
106111 }
107112 }
0 commit comments