Swift has one of the coolest type systems out there and I think that it is greatly underused by the average programmer.

Let me give you an example of what I mean. Let’s say that somewhere in your app you need to store user’s email address. What’s the perfect data type to store an email address? String , right? Wrong, that’s not what you should be looking for. What you need is the Email type, a custom type that you will have to write yourself (or grab it on GitHub). The problem in using strings to store emails is that strings can be virtually anything: zero length, giga-character length, have all sorts of characters and end up having no @ symbol at all. Clearly the vast majority of values that a string can hold are not a valid email address.

Adapted from Rob Napier talk on types: https://youtu.be/_S6UOrwS-Tg?t=619

So why do you want all that enormous possibility of invalid values jumping around in your code? You might say that you validate the user input, probably inside a setter or with a function that you have to call more than once. Ok, that might work, but given a function that receives a String that is supposed to be a valid email address, you won't be sure that it will always be a valid email address and probably end up double checking with something like this:

Not to say that when calling this function, if you accidentally change the parameters orders like send(email, to: message) you will only notice that in runtime.

Definitely not a cool user experience

So let’s apply the title of this article and bring this issue to compile-time.

Those few lines solves all of the problems listed above, the most relevant of them: when you have a variable of type Email you can be sure that it holds a valid email address, in fact, as you can see the isValid function is private because it would never be needed outside that init . The validation is made only once, when you create the email instance. As soon you unwrap that optional (because it’s a failable init ) it’s done, you have a valid email address, period.

From the same Rob Napier talk https://youtu.be/_S6UOrwS-Tg

Now in your send(message:, to:) you can go straight to business.

Another benefit is that a typo like send(email, to: message) will not compile. The compiler (and your type safe code) just saved you a runtime bug.

And what about the message? String is a good data type to hold the message? It might be or it might not be. Suppose that the email message has to be at most 1024 bytes long and also that it have to use CRLF line break style. In that case String clearly is not a good data type to hold the message.

This will probably be a better solution, since at any time you know that a EmailMessage will have a valid email message and the compiler will enforce that for you. Also you will never double validate the same message.

There are plenty of examples of custom value types that will help you write a safer code. Here are a few, that I came across being stored as strings or even worse, as numerical types:

Phone numbers

SSN (social security number)

Usernames

Passwords

Zipcodes

As you can see, both structs ( Email and EmailMessage ) have a similar code. That repetition can be avoided with the use of generics.

Let’s create a generic ValidatedString :

Now, whenever you need a new type that’s simply a validated and sanitized string you just need to create a validator that conforms to ValidatedStringValidator .

The validators for the two examples above will be:

With that typealias we don't need to use the whole generic syntax everytime, so the interface stays the same as in the examples first examples.

If you notice, Swift and the Foundation framework don’t skimp on creating new data types, they create a new enum for every possible situation, there’s the URL type when at first look a String would be good enough. So, that’s not a new thing in Swift development but I still don’t see it applied very much.

Other Cool Stuff

With those custom types you can add all sort of custom behaviour like:

Computed properties

Custom equatables and hashables

This Money type that don’t allow you to mix different currencies:

Adapted from Mattt’s (awesome) book @ https://flight.school/books/numbers/

This type safe file path that only allows you to append path components to directory paths, and gives a compile error if you try to append to a file path: