Creating wrapper types for raw values, such as strings and integers, can be a great way to make our code a bit more type-safe and self-documenting — and also gives us dedicated types on which we can implement domain-specific convenience APIs.

For example, here’s such a type that represents a file system path, which can be used to do things like load the contents of a file:

struct Path { var string: String } func loadFile(at path: Path ) throws -> File { ... }

However, while having that dedicated Path type does give us several benefits, it could also make our APIs a bit more cumbersome to use. For example, anytime we want to specify a path using a string literal, we now have to wrap it first:

try loadFile (at: Path (string: "~/documents/article.md" ))

To fix that, we can make Path conform to ExpressibleByStringLiteral , which enables us to directly pass a string literal to any API that accepts a Path :

extension Path : ExpressibleByStringLiteral { init (stringLiteral value: String ) { self . string = value } } try loadFile (at: "~/documents/article.md" )

That’s really nice, however, the above won’t work if we’re using any form of interpolation within our string — such as in this case:

try loadFile (at: "/users/ \(username) /file.txt" )

Thankfully, the above problem is easily fixed. All we have to do is to declare that our Path also conforms to ExpressibleByStringInterpolation — and the compiler will be able to infer the rest:

extension Path : ExpressibleByStringInterpolation {}

We can now express our Path type using any kind of string literal — which makes it much more convenient to use, while still giving us all of the benefits of stronger typing.

Support Swift by Sundell by checking out this sponsor: