Swift typealias to the rescue

Writing async code in Swift is (mostly) a joyful experience. Things can get a bit hairy, though, when writing something like an API Client where functions 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 little 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.

Since functions and closures in Swift have a type (consisting of the function’s parameter types and return type) they 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 eye, 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 they can be called as usual.

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

Disclaimer: while I think this is a good idea in cases where you have a few closure types used by a majority of a class’s functions, I would be cautious when you have a lot of closure types used by only a few functions. Doing so will introduce indirection into your code without much benefit.

All patterns have trade-offs, and in this case it’s increased indirection for less duplication. There is no magic bullet!

Thoughts? Feedback? Disagreements? Twitter me: @mattvague