Type utilities are essentially functions for our types in TypeScript. We'll create a type utility named Brand
that will accept a primitive type and the name of the brand.
This will allow us to easily create Brand types throughout our application like the following:
type Email = Brand<string, "EMAIL">;
type DateString = Brand<string, "DATE_STRING">
Email
and DateString
are both strings at the end of the day but you cannot assign a DateString
to an Email
or visa versa.
[00:00] In order to create brand types, first, let's create the brand type utility, which will accept 2 type parameters. First is the base type, which is going to be the type that we're extending. So number in case of money and string in case of email. The second type parameter is the [00:19] brand name, which will allow us to create multiple brands of number, multiple brands of string, making them incompatible between each other. So having these two type parameters, we can start and extend the base type the same way as we did already. [00:39] And here we would also create a read only property. However, this time, we don't want to make it publicly visible. What is the name of the property? Just to make it even more bulletproof, we're going to put a JavaScript symbol over here. So for this reason, let's just declare one more symbol, which [00:59] we're going to call, let's say, brand underscore type, which is going to be a unique symbol. So anybody who doesn't have access to this unique symbol will be unable to not only modify, but also read the value over here. So behind this brand type [01:19] symbol key of the object, what we're going to put here is the brand name. So let's now update the declaration of our money, alias, which is going to be brand and the base type is, of course, number and the brand name is money. Let's also update the [01:39] email to be the brand of string of type email. An important aspect of the declaration of the brand type utility is that the name of the brand becomes part of the type. In other words, when we take a look at the email brand, we can see that this is not [01:59] just a string, but this is a very specific string. This is the name of the brand. This will help us to create multiple brands of the same base to be incompatible between each other. And so we would create a date string, which could be also a formatted version of a certain string. So let's just make it [02:19] date string. So we can see that the email includes a certain value under the brand type symbol and the date string includes a different value over here. So essentially on the structural typing level, these structures are different, so they are [02:38] essentially incompatible. So let's see this in action. If we declare a const email, which is of the email brand, and we declare the date string, which is of the date string brand, and we will just replace these with let [02:58] so that we can check whether they are compatible when trying to assign one to the other, we will see that both are not compatible because the shape of the object, the shape of the brand over here is different. So in order to create a brand type, you can [03:18] just create the brand using the type utility, and you don't need to know all the specific details of the brand type utility declaration.