question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Instead of:

type Age = Branded<number, "Age">;

const Age = z
  .number()
  .min(0)
  .max(100)
  .refine((a: number): a is Age => true);

Zod can provide a simple helper:

const Age = z
  .number()
  .min(0)
  .max(100)
  .brand('Age');

What do you think?


This line:

.refine((a: number): a is Branded<number, "Age"> => true)

to this line:

.brand("Age").

I suppose it’s a tiny change but would improve DX a lot.


Or something like that?

const brand =
  <B extends string>(brand: B) =>
  <T extends string | number>(a: T): a is Branded<T, typeof brand> =>
    true;

.refine(brand("Age"))

OK, this is what I reiterated. Still, I suppose it should be part of the official Zod API.

export type Branded<T extends string | number, B extends string> = T & {
  readonly __brand: B;
};

export const branded =
  <B extends string, T extends string | number>(
    brand: B,
    predicate?: Predicate<T>
  ) =>
  (a: T): a is Branded<T, typeof brand> =>
    predicate ? predicate(a) : true;

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Reactions:1
  • Comments:8 (1 by maintainers)

github_iconTop GitHub Comments

5reactions
brudilcommented, Feb 23, 2022

We use branded types a fair bit, so I’m happy to chime in on how they can be used.

With TypeScript’s structural typing, we can’t utilise the type system to ensure zod is being used. Branded types are a way to create a unique type which can only be assigned by parsing with zod. This allows us to use the type system to ensure validation is happening.

As an example;

Defining a schema such as

const Age = z.number().min(18);

And we can use the inferred type from our schema within a param for example.

function save(data: z.infer<typeof Age> ) {}

TypeScript’s structural typing means there are no guarantees that input needs to have been parsed by zod first.

save(16) // perfectly valid and types.

Branded types allow us make a type ‘unique’.

export type Branded<T, B> = T & { __brand: B };

If we revisit the save function from above

function save(data: Branded<z.infer<typeof Age>, 'ageSchema'> ) {}

We’ve now ensured that this case is no longer possible

save(16)
// TS2345: Argument of type 'number' is not assignable to parameter of type 'Branded<number, "ageSchema">'.   Property '__brand' is missing in type 'number' but required in type '{ __brand: "ageSchema"; }'.

(Edited to a primitive)

2reactions
colinhackscommented, Mar 1, 2022

I’ll I’ve been considering a dedicated API for branded types for a long time (#3) but I think the current approaches are more or less equivalent in terms of readability to a dedicated .brand API. If you want the result of .parse to be pretty (e.g. Age), you have to declare that type separately. At that point you might as well cast or use z.custom:

type Age = Branded<number, "Age">;

const ageSchema: z.ZodType<Age> = z.string().refine(...) as any;
const ageSchema = z.custom<Age>()

Open to be convinced though.

Read more comments on GitHub >

github_iconTop Results From Across the Web

The Helper Brands
The Cleaner's Helper brand serves the professional cleaning industry, focusing on Carpet Cleaners, Cleaning Companies, and Housekeeping staff. Learn More About ...
Read more >
The Helper Brands @ Amazon.com:
Online shopping from a great selection at The Helper Brands Store. ... Handy Helper Tool Belt, Organizer, Carrier for Home, Garden, RV -...
Read more >
Helper – Brands – Food we make - General Mills
With more than 60 flavor varieties, the Helper lineup has been a staple for busy family dinners since 1970. It's deliciousness, convenience and...
Read more >
Helper - BettyCrocker.com
Betty Crocker Chicken Helper, Fettuccine Alfredo, 8.7 oz. Shop Product ... Hamburger Helper, Bacon Cheeseburger Macaroni Meal, 5.1 oz. Shop Product.
Read more >
Brand: Ultimate Helper - Walmart.com
how to draw all the things for kids : drawing helper for kids - the ultimate guide for fast & simple learn (...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found