Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature: add branded types #56

Closed
zkulbeda opened this issue Aug 4, 2023 · 8 comments
Closed

feature: add branded types #56

zkulbeda opened this issue Aug 4, 2023 · 8 comments
Assignees
Labels
enhancement New feature or request

Comments

@zkulbeda
Copy link
Contributor

zkulbeda commented Aug 4, 2023

Introduce brand method

const BrandType: unique symbol = Symbol()

interface Brand<K extends string | symbol> {
  readonly [BrandType]: {
    readonly [k in K]: K
  }
}

type Branded<T, K extends string | symbol> = T & Brand<K>

function brand<TSchema extends BaseSchema, const K>(
  schema: TSchema,
  brand: K
): BaseSchema<Input<TSchema>, Branded<Output<TSchema>, K>>{
  return schema
}

const schema = brand(number([maxValue(20)]), "UserId");
parse(schema, 123) // number & Brand<"UserId">
@fabian-hiller
Copy link
Owner

Can you explain in which specific use cases brand is useful and offers an advantage? I have not quite understood it yet.

@fabian-hiller fabian-hiller self-assigned this Aug 4, 2023
@fabian-hiller fabian-hiller added enhancement New feature or request question Further information is requested labels Aug 4, 2023
@zkulbeda
Copy link
Contributor Author

zkulbeda commented Aug 4, 2023

Nominal type matching is highly requested typescript feature, and until typescript doesn't have it, branded types is alternative.

See some resources of using them
https://egghead.io/blog/using-branded-types-in-typescript
https://twitter.com/mattpocockuk/status/1625173884885401600

@fabian-hiller
Copy link
Owner

I think I understand it now. Cool idea. Once I'm done with my bachelor thesis and hopefully have some more time, I can take a closer look at it.

@fabian-hiller fabian-hiller removed the question Further information is requested label Aug 4, 2023
@zkulbeda
Copy link
Contributor Author

zkulbeda commented Aug 4, 2023

Thanks! I should mention that zod also have brand utility, docs. I think it would simplify migration to valibot. See later great example of implementing nominal types in other lib @effect/data

@fabian-hiller
Copy link
Owner

If you have time and interest, you can try to implement this feature and submit a PR. I will check your code and give you feedback.

@fabian-hiller
Copy link
Owner

The brand feature is now available 🎉

@danielo515
Copy link

danielo515 commented Sep 11, 2023

@fabian-hiller if you have finished your degree and you are not yet familiar with this, then you are missing one of the best type safety features and it's a good time for you to investigate it 😁. This exists in several languages with different names, but the same concept:

  • ocaml: phantom types
  • rust: newtype pattern
  • F# constrained types (I think)

Since you seem to be interested in the type safety topic I really recommend taking a look at "domain modeling made functional", for some eye-opening usage examples. For me they are super valuable for IDs (what is that string? A user ID or a car ID?)

@fabian-hiller
Copy link
Owner

Thank you. I will have a look at it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

3 participants