It’s been so fun to watch the Swift developer community experiment with Swift and to experiment with what idiomatic Swift will look like. No one really knows the answer yet, but we’re starting to see some design patterns used more than others. We’re seeing some language features used in key ways that define idiomatic Swift, and other language features that are being mostly ignored.
Regrettably, one of my favourite features of Swift has not enjoyed the meteoric rise in popularity I believe it deserves: typealias
.
Type aliases allow developers to define synonyms for pre-existing types. It might sound dull because it is dull. In fact, its usefulness isn’t even apparent when writing code, mostly when maintaining it.
But before I dig into how typealias
is useful, let’s review what it is to make sure we’re all on the same page. Developers use typealias
to create a new type identifier that’s a synonym for another type. For example, we can declare typealias BigNumber = Int64
and use “BigNumber” any place we could have used “Int64”.
func multiply(lhs: BigNumber, rhs: BigNumber) -> BigNumber
...
let number: BigNumber = 5
...
let number = BigNumber(5)
You can use typealias
for most any type: classes, enums, structs, tuples, closures, etc. Here are a few examples.
typealias Name = String
typealias Employees = Array<Employee>
typealias GridPoint = (Int, Int)
typealias CompletionHandler = (ErrorType?) -> Void
Now that we’re familiar with typealias
, I want to discuss four examples that show how typealias
has helped us maintain code.
Promoting Existing Types Semantics
When writing web socket communication for eigen, Orta and I were using JSON Web Tokens to authenticate the user. If you’ve never used JWTs before, don’t worry, here’s the tl;dr JWTs are a way to authenticate users in a way that clients can cryptographically verify. It’s basically a base64 encoded string of JSON.
Clients don’t need to verify the JWT in order to use them, and in fact when Orta and I began using them, we treated them only as strings retrieved from one API and sent to another (like an access token). However, instead of using the String
type, I decided to define a JWT
type alias.
typealias JWT = String
I used the new JWT
type throughout the code as a hint to other developers about what kind of string it is. This gave it some semantic meaning on top of being a string. Neat. Only later, when we needed to start decoding the JWT itself did this really come in handy.
After deleting the typealias
and replacing it with a class of the same name, we didn’t have to worry about changing function definitions and property types all throughout our codebase. We made the changes locally, in one file, and most all the rest of our code still compiled. Pretty cool! Here’s the relevant portion of the pull request that made that change.
Consolidating Tuple Types
I recently wrote about UICollectionView and how I used them to solve a difficult layout problem. I detailed how I created a pipeline of simple math functions that used previous results to calculate the next step of the layout. What I didn’t mention was that I used tuples to help, specifically tuples with typealias
.
Tuples are useful for composing several different values into a lightweight type. Think of tuples as junior structs. I was writing functions to do some calculations and return their result as a tuple. Something like this:
func layoutMetricsForPosition(position: CellPosition, aspectRatio: CGFloat) -> (restingWidth: CGFloat, restingHeight: CGFloat, targetWidth: CGFloat, targetHeight: CGFloat)
And because of how the layout pipeline worked, I then needed to use the same tuple as a parameter for the next function.
func centersForPosition(position: CellPosition, metrics: (restingWidth: CGFloat, restingHeight: CGFloat, targetWidth: CGFloat, targetHeight: CGFloat)) -> ...
Any time you use the same tuple type more than once, consider making a typealias
. In this case, the code became a lot shorter and easier to skim and understand.
typealias LayoutMetrics = (restingWidth: CGFloat, restingHeight: CGFloat, targetWidth: CGFloat, targetHeight: CGFloat)
typealias CenterXPositions = (restingCenterX: CGFloat, targetCenterX: CGFloat)
func layoutMetricsForPosition(position: CellPosition, aspectRatio: CGFloat) -> LayoutMetrics
func centersForPosition(position: CellPosition, metrics: LayoutMetrics) -> CenterXPositions
If we need to change something about the tuple later on, we only need to change it in one place. We’ve also made it easier to promote this tuple to a struct or class later on, just like in the JWT example, because all the functions are already referring to it as its own type. You can check out how we used type alias’d tuples in the code.
Defining Closures Signatures
Objective-C developers, burdened with arcane syntax for blocks, use C’s typedef
to isolate that syntax strangeness in one place. And even though Swift’s closure syntax is awesome, we can still benefit from Objective-C’s example – we can use type aliases for closure signatures.
Moya uses this technique quite a bit, because it has so many closures. Let’s take a look at the StubClosure
, which defines if (and how) a network request should be stubbed.
typealias StubClosure = Target -> StubBehavior
We use this type as an initializer parameter instead of the full closure syntax, making our code a lot shorter and more legible. Nice! Since the user usually doesn’t want to customize this parameter, so we’ve defined a default value.
init(...
stubClosure: StubClosure = MoyaProvider.NeverStub,
...)
MoyaProvider
has a class function on it called NeverStub
whose type matches our closure.
class func NeverStub(_: Target) -> Moya.StubBehavior {
return .Never
}
This particular function doesn’t use the typealias
, but another one does. We have a function named DelayedStub
that returns the typealias
instead of the raw closure. Take a look!
class func DelayedStub(seconds: NSTimeInterval) -> Moya.StubClosure {
return { _ in return .Delayed(seconds: seconds) }
}
Super cool! Closures are a powerful tool in Swift already, but by using a typealias
, we refer to it as StubClosure
throughout our code.
In isolation, this gain may not seem significant, but the dividends have accrued dramatically for the project. typealias
has made it easy to maintain Moya as it has evolved alongside Swift. Check out more examples of type aliasing closures in this eigen class, which uses them for dependency injection.
Extending Typealiases
The last example I want to discuss is extensions, specifically extensions to your own types.
When writing classes, especially view controllers, developers have a habit of writing long, unwieldy files that are difficult to navigate and maintain. Preventing such files is far easier than fixing them, which is why I use typealias
early, and I use it often.
I recommend using a descriptive typealias
that is private to your file, and then extending that typealias
so you can keep things neat and tidy. It’s a bit confusing, so let’s take a look at an example.
private typealias PrivateHelperFunctions = MyViewController
extension PrivateHelperFunctions {
...
}
private typealias TableViewMethods = MyViewController
extension TableViewMethods: UITableViewDelegate, UITableViewDataSource {
...
}
We’re still extending the view controller, but specifically we’re extending the typealias
so that the extension has a helpful name. This is another way that typealias
can help add semantic meaning to your code.
Beyond helping you find code quickly, having code in extensions also makes it way easier to move that extension to another file or create a new helper class altogether. So not only does it keep classes tidy, but it also helps you keep classes small.
This technique can also serve as a workaround for Swift’s awful Xcode sectioning syntax.
You can search through eigen for more examples of using a private typealias
to divide your code into manageable pieces.
Look, I’m not saying that using typealias
more is universally a good idea. You might disagree with some of the use cases in this post, which is fine! And this isn’t meant to be an exhaustive list of examples, either.
My point is, used in a few key ways, typealias
has helped me maintain my code more easily. It’s a good tool to be familiar with. Even if it won’t revolutionize the way you write software, typealias
can help make your job a smidgen easier, and who could argue with that?