- All posts
- A typealias can take a type parameter
A typealias can take a type parameter
Naming a completion handler once and writing Handler<Post> at each call site. It gives you readability and a single place to change the signature. It does not give you type safety.
A typealias does one thing: it gives an existing type a second name. Apple’s
own TimeInterval is one, aliasing Double. It says what the number means,
and it leaves room for the underlying type to change without every mention of
it changing too.
The version I use most often takes a type parameter:
struct Service {
typealias Handler<Response> = (Result<Response, APIError>) -> Void
func fetchPost(id: Int, _ completion: @escaping Handler<Post>) { ... }
func fetchPosts(_ completion: @escaping Handler<[Post]>) { ... }
func fetchBooks(_ completion: @escaping Handler<[Book]>) { ... }
}
Without it, each of those signatures carries
(Result<Post, APIError>) -> Void in full, and the shape of the API — every
call returns a Result with the same error type — is something the reader has
to assemble from three lines that all look slightly different. With it, the
shape is stated once and only the response type changes.
It also gives you somewhere to make a change. When the error type moves from
APIError to something else, it moves in one line rather than in every
signature that mentions it.
The other use is shortening a name you did not choose:
final class Service {
typealias Book = SLBSomeLibraryServiceBookModel
func loadBooks() -> [Book] { ... }
}
That is safe inside a type, where the alias is scoped and a reader can find the
declaration. At file scope it needs more care: Book from three different
modules means three different things.
What none of this gives you is type safety. Handler<Post> and
(Result<Post, APIError>) -> Void are the same type, not two types that happen
to be spelled differently — there is no distinction the compiler will enforce
and no overload it will resolve differently. If you want the compiler to know
that a service’s completion is not just any closure, the alias is the wrong
tool and a wrapper type is the right one.
It is documentation that the compiler checks for spelling. It is not a type.
Antoine van der Lee has a longer piece on typealias that is worth the ten minutes.