const Email = ValidatedBrand("Email", (s: string) => /^[^@]+@[^@]+\.[^@]+$/.test(s))
const email = Email.of("user@example.com") // Some(Brand<"Email", string>)
// With Either for error messages
const Port = ValidatedBrand("Port", (n: number) => n >= 1 && n <= 65535)
const result = Port.from(8080) // Right(Brand<"Port", number>)
const error = Port.from(70000) // Left("Invalid Port: validation failed")
// Type guard usage
const value: unknown = "test@example.com"
if (Email.is(value)) {
// value is Brand<"Email", string>
}
// Best Practice: Use same brand name for seamless conversion
// ValidatedBrand extends Brand, so when using the same brand name,
// no casting is needed for conversion
const ValidatedUserId = ValidatedBrand("UserId", (s: string) => s.length > 0)
type ValidatedUserId = ReturnType<typeof ValidatedUserId.of> extends Option<infer T> ? T : never
type UserId = Brand<"UserId", string>
const toSimpleUserId = (id: ValidatedUserId): UserId => id // No cast needed!
// Avoid different brand names which require casting:
// ❌ ValidatedBrand("ValidatedUserId", ...) + Brand<"UserId", string>
// ✅ ValidatedBrand("UserId", ...) + Brand<"UserId", string>
Create a validated brand with runtime validation