arktypeio / arktype

TypeScript's 1:1 validator, optimized from editor to runtime
https://arktype.io
MIT License
3.88k stars 57 forks source link

Branded Types #741

Open cogell opened 1 year ago

cogell commented 1 year ago

Request a feature

🤷 Motivation

What problem are you having?

In applications having Branded types improves some of the confidence around our code base. We can parse a user email at the edge of the application, brand that with a symbol, and then in components, assume the string we have is indeed a valid email.

// in Zod
const Email = z
  .string()
  .refine(isEmail)
  .brand<"Email">();

Why should we prioritize solving it?

This would be one less hurdle for people moving from zod or io-ts to arktype.

💡 Solution

How do you think we should solve the problem?

Given the Arktype beta future looking toward chaining, perhaps:

const Email = type('string')
  .morph(isEmail)
  .brand("Email");

Why do you think this is the best solution?

Im not highly confident it is. How would with work in the parseOperator...?

ssalbdivad commented 1 year ago

It is unlikely this would be built-in as an operator, but would instead be made available as part of our generics implementation via something like Branded. This would also allow it to be chained in a way similar to what you have shown, in addition to:

const email = type("Branded</.*@.*/, 'email'>")

Would depend on #425. That should be one of the first things we tackle after the beta release though.

nlynzaad commented 1 month ago

Found this issue while looking to see if there was a built in method.

The below seems to work with the latest version

declare const __brand: unique symbol;

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

type Email = Branded<string, 'email'>;

const types = scope({
  "Email": type("email") as Type<Email>
}).export()

image

image

ssalbdivad commented 1 month ago

I think ideally what I'd like to do is to reuse the existing string.narrowed and number.divisbleBy<1> constructs I have now, but to add some logic to that to allow giving names to custom predicates?

Would be really cool to preserve the set-based comparisons for cases where it's possible.

nirweiner2 commented 1 month ago

Hi. I was wondering if there was any progress on this? (I thought I may have seen some commits related?)

ssalbdivad commented 1 month ago

Yes, there's been quite a lot of progress here! There's this very detailed constraint branding system that you will see if you hover over any type you create.

image

At some point soon now that we're approaching a stable 2.0, I will finalize this syntax, the internal type representation, and the APIs and/or configs that can be used to have a type return its branded variant or add arbitrary brands to an existing type.

nirweiner2 commented 1 month ago

I am really looking forward for this to be fully stable. It would allow us to finally migrate from zod and improve our vscode performance :) Thank you very much for all the hard work.