UNPKG

zod

Version:

TypeScript-first schema declaration and validation library with static type inference

54 lines (41 loc) 1.73 kB
// @ts-ignore TS6133 import { test } from "vitest"; import * as z from "zod/v3"; import { util } from "../helpers/util.js"; test("branded types", () => { const mySchema = z .object({ name: z.string(), }) .brand<"superschema">(); // simple branding type MySchema = z.infer<typeof mySchema>; util.assertEqual<MySchema, { name: string } & { [z.BRAND]: { superschema: true } }>(true); const doStuff = (arg: MySchema) => arg; doStuff(mySchema.parse({ name: "hello there" })); // inheritance const extendedSchema = mySchema.brand<"subschema">(); type ExtendedSchema = z.infer<typeof extendedSchema>; util.assertEqual<ExtendedSchema, { name: string } & z.BRAND<"superschema"> & z.BRAND<"subschema">>(true); doStuff(extendedSchema.parse({ name: "hello again" })); // number branding const numberSchema = z.number().brand<42>(); type NumberSchema = z.infer<typeof numberSchema>; util.assertEqual<NumberSchema, number & { [z.BRAND]: { 42: true } }>(true); // symbol branding const MyBrand: unique symbol = Symbol("hello"); type MyBrand = typeof MyBrand; const symbolBrand = z.number().brand<"sup">().brand<typeof MyBrand>(); type SymbolBrand = z.infer<typeof symbolBrand>; // number & { [z.BRAND]: { sup: true, [MyBrand]: true } } util.assertEqual<SymbolBrand, number & z.BRAND<"sup"> & z.BRAND<MyBrand>>(true); // keeping brands out of input types const age = z.number().brand<"age">(); type Age = z.infer<typeof age>; type AgeInput = z.input<typeof age>; util.assertEqual<AgeInput, Age>(false); util.assertEqual<number, AgeInput>(true); util.assertEqual<number & z.BRAND<"age">, Age>(true); // @ts-expect-error doStuff({ name: "hello there!" }); });