Swift typealias to the rescue

Matt Vague
Feb 9, 2015 · 3 min read

Writing async code in Swift is (mostly) a joyful experience. Things can get hairy though when writing something like an API Client with functions that accept multiple closure arguments, which themselves accept multiple arguments.

Example:

class ApiClient {  // ....  func getUsers(success: ((result: AnyObject, operation: AFHTTPRequestOperation) -> Void)? = nil,
error: ((error: NSError, operation: AFHTTPRequestOperation) -> Bool)? = nil,
finished: (() -> Void)? = nil) {
// Do stuff
}
func getUser(user: User, success: ((result: AnyObject, operation: AFHTTPRequestOperation) -> Void)? = nil,
error: ((error: NSError, operation: AFHTTPRequestOperation) -> Bool)? = nil,
finished: (() -> Void)? = nil) {
// Do stuff
}
func getInvitations(success: ((result: AnyObject, operation: AFHTTPRequestOperation) -> Void)? = nil,
error: ((error: NSError, operation: AFHTTPRequestOperation) -> Bool)? = nil,
finished: (() -> Void)? = nil) {
// Do stuff
}
// ....}

Not only is this painful to read, there’s also a lot of needless repetition leading to a high probability of copy-paste-itis. There is a better way!

Introducing typealias

Luckily, Swift’s got our backs here with a handy feature called typealias.

From the Swift Docs:

A type alias declaration introduces a named alias of an existing type into your program. Type alias declarations are declared using the keyword typealias and have the following form:

typealias name = existing type

After a type alias is declared, the aliased name can be used instead of the existing type everywhere in your program. The existing type can be a named type or a compound type. Type aliases do not create new types; they simply allow a name to refer to an existing type.

Functions and closures in Swift have a type (consisting of the function’s parameter types and return type) and so can be aliased like anything else:

typealias MyFunctionDefinition = (Integer, String) -> Void

Applying that to our example API client, we end up with this:

class ApiClient {  // ....  typealias SuccessHandler = (result: AnyObject, operation: AFHTTPRequestOperation)
-> Void
typealias ErrorHandler = (error: NSError, operation: AFHTTPRequestOperation)
-> Void
typealias FinishedHandler = () -> Void
func getUsers(success: (SuccessHandler)? = nil,
error: (ErrorHandler)? = nil,
finished: (FinishedHandler)? = nil) {
// Do stuff
}
func getUsers(success: (SuccessHandler)? = nil,
error: (ErrorHandler)? = nil,
finished: (FinishedHandler)? = nil) {
// Do stuff
}
func getInvitations(user: User,
success: (SuccessHandler)? = nil,
error: (ErrorHandler)? = nil,
finished: (FinishedHandler)? = nil) {
// Do stuff
}
// ....}

To me those function definitions are now a lot easier to read, and undeniably easier to write. Best of all, this is a drop-in solution. Nothing else about your functions need change and everything can be called as before.

ApiClient.sharedInstance.getUsers(success: { result, operation in
// Do stuff
}, error { error, operation in
// Do stuff
}, finished {
// Do stuff
})

Disclaimer: This pattern works well where you have a few closure types used by a majority of a class’s functions, but I would be cautious when you have many closure types used by only a few functions. Doing so may introduce indirection into your code without much benefit.

All patterns have trade-offs, and in this case we’re trading increased indirection for decreased duplication. There are no magic bullets!

Thoughts? Feedback? Disagreements? Twitter me: @mattvague

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store