typealias
in SwiftAlias generally refers to an assumed identity or an alternate name that a person is known by — maybe a nickname, pen name, nom de plume, or pseudonym. In programming terms, an alias is very similar.
In Swift, typealias
is a function that gives a new name, or an alias, to an existing type. This type can be a concrete type, like Double
or a custom structure, a compound type, like tuples, or a complex closure type. By providing an alias for existing types, typealias
helps make our code more readable and easier to maintain.
Here’s a fun fact: there are 363 typealias
present in the Foundation framework as of this writing! So, let’s take a look at the power of typealias
and consider how we can strike a balance between its function and its usefulness!
Jump ahead:
typealias
with cautionThe syntax for declaring a new typealias
in Swift looks like this:
typealias aliasName = existingType
Note that aliasName
is not a new type; it refers to the existing type.
Let’s say our project has messages in the form of a String
:
var message: String?
Instead, we can use a typealias
to call the String
with an alias name, Message
:
typealias Message = String
Then, we can use it in our codebase, like so:
var message: Message?
Here are some basic examples of instances in which typealias
can be particularly helpful:
A very basic, but widely used, example is to specify a time interval with a particular alias even though the type is Double
:
typealias TimeInterval = Double
Another example is when we use a unique identifier for a user. We can create a typealias
, like so:
public typealias UserID = String
Then, whenever we declare a user ID, we can simply use the typealias
name:
public let userID: UserID var currentUserID: UserID? func createUser(for id: UserID) { /// implementation }
Apps that rely heavily on displaying and calculating scores are great candidates for typealias
. We can create a typealias
for the type of the score, like so:
typealias Score = Double
Then, we can use Score
everywhere instead of using Double
:
struct RGBColorScore { var red: Score var green: Score var blue: Score
Or, use it while defining a variable:
var currentScore: Score
Or, use it as the return type of a method:
func calculateMaximumScore(for score: RGBColorScore) -> Score { max(score.red, score.green, score.blue) }
typealias
is helpful when we want to give appropriate naming to the type that fits better contextually. For example, if we’re working on a screen related to login and sign up, we can create a typealias
for the password:
typealias Password = String
We can perform various validation checks on the password and use Password
instead of String
because it is more contextually appropriate in this situation:
func passwordLengthValidation(for password: Password) -> Bool { password.count > 8 }
Now, let’s look at some more advanced scenarios where typealias
can come in handy in our codebase.
When working with types that are just too wordy, you may find it helpful to use an alternative name instead. For example, working with diffable data sources is amazing, but the name of the generic classes are verbose.
Having these wordy types sprinkled across our codebase can cause headaches.
One solution to address excess verbosity is to use typealias
. Here’s an example of using typealias
with a diffable data source:
typealias DataSource = UICollectionViewDiffableDataSource<Section, Item> private var dataSource: DataSource?
Here’s an example of using it in our codebase:
typealias CurationSnapshot = NSDiffableDataSourceSnapshot<CurationCardSection, CurationCardModel> typealias CurationDataSource = UICollectionViewDiffableDataSource<CurationCardSection, CurationCardModel>
If you have worked with the reducer pattern, you’re familiar with the state, action, and environment arguments. It can get cumbersome to continually write these arguments.
Instead, we can use typealias
:
typealias AppReducer = Reducer<AppState, AppAction, AppEnvironment>
Another use case is when you’re working with a protocol in which you use the same type repeatedly.
For example, let’s say we create a protocol Stack
that uses Element
. All the functions and variables would have to use the associated type as Iterator.Element
instead of Element
.
Instead, we can use typealias
, like so:
protocol Stack { associatedtype Iterator: IteratorProtocol typealias Element = Iterator.Element var array: [Element] { get set } func push(_ element: Element) func pop() -> Element? func peak() -> Element? }
typealias
can improve readability for any named types that have long names; both user-defined types and those provided by the Foundation framework.
Many instances of long type names can be found in the Foundation framework. For example, different enumerations were introduced by Apple at its 2021 Worldwide Developers Conference (WWDC21) for formatting and parsing numeric values for numeric precision, rounding, and scale:
enum NumberFormatStyleConfiguration enum CurrencyFormatStyleConfiguration
To access each configuration, we need to use the dot syntax, such as NumberFormatStyleConfiguration.Grouping
. But, the dot syntax makes the name even longer, and using the longer name everywhere is cumbersome.
Instead, we can create custom typealias
with shorter, more explicit names:
public typealias NumberGrouping = NumberFormatStyleConfiguration.Grouping public typealias CurrencyPrecision = CurrencyFormatStyleConfiguration.Precision
Here are some of many similar examples available from the Foundation framework:
public typealias EncodingConversionOptions = NSString.EncodingConversionOptions public typealias EnumerationOptions = NSString.EnumerationOptions public typealias CompareOptions = NSString.CompareOptions
As another example, Shopify’s iOS SDK uses typealias
to create shorter names:
public typealias Query = FulfillmentLineItemConnectionQuery public typealias Response = FulfillmentLineItemConnection
There are many instances with first-party frameworks where we can make a name more concise by introducing typealias
when accessing types of that particular framework.
Let’s take the example of Apple’s MusicKit framework. It has a generic structure, MusicItemCollection<MusicItemType>
, where MusicItemCollection
is a collection of music items and MusicItemType
conforms to MusicItem
.
To fetch multiple songs from Apple Music matching the particular identifiers, we write the following method:
func catalogSongs(ids: [MusicItemID]) async throws -> MusicItemCollection<Song> { let musicRequest = MusicCatalogResourceRequest<Song>(matching: \.id, memberOf: ids) let response = try await musicRequest.response() return response.items }
In our model, we pass the ids
and then set the songs
returned by this method to a variable:
var songs: MusicItemCollection<Song>? songs = try await catalogSongs(ids: ["1109658204", "1508562321"])
Now, let’s use typealias
to create a shorter name, Songs
, for MusicItemCollection<Song>
.
We can use this shorter name everywhere to improve readability:
typealias Songs = MusicItemCollection<Song> func catalogSongs(ids: [MusicItemID]) async throws -> Songs { let musicRequest = MusicCatalogResourceRequest<Song>(matching: \.id, memberOf: ids) let response = try await musicRequest.response() return response.items } var songs: Songs? songs = try await catalogSongs(ids: ["1109658204", "1508562321"]) /// More examples var recommendedSongs: Songs? var recentlyPlayedSongs: Songs? var frequentlyPlayedSongs: Songs?
This strategy can be applied to all generic structures, making them easier to read and understand:
public typealias Artists = MusicItemCollection<Artist> public typealias Genres = MusicItemCollection<Genre> public typealias Albums = MusicItemCollection<Album>
Shorter, more concise aliases improve code readability!
We can utilize the power of typealias
when working with complex types that have several arguments. For example:
typealias QuoteCompletion = (Result<Quote, Error>) -> () typealias QuotesCompletion = (Result<[Quote], Error>) -> ()
Then, in our methods, we can use the more succinct typealias
name:
typealias QuoteID = String func fetchAllQuotes(completion: @escaping QuotesCompletion) { /// implementation } func fetchQuote(for ID: QuoteID, completion: @escaping QuoteCompletion) { /// implementation }
Now, let’s look at a more complex example simplified using typealias
. Here’s a generic closure that has constraints on the type:
typealias Parser<A> = (String) -> [(A, String)] where A: Equatable
We can use it like so:
func parsing<A>(_ string: String, for parser: Parser<A>) where A: Equatable { }
You may have had cases where your class
or struct
conforms to many protocols. For clarity, we can combine the series of protocol conformances into a single typealias
and then use that alias everywhere.
typealias CombinedType = FooProtocol & BarProtocol
A classic example is when we are conforming our UIViewController
to different delegates. For example, say we have a controller that is presented as a popover, and we want to conform to UIPopoverPresentationControllerDelegate
to get the delegate methods.
If we have many controllers, we can create a typealias
:
typealias PresentableViewController = UIViewController & UIPopoverPresentationControllerDelegate
In the MusicKit framework, Apple takes a similar approach with typealias
. In this case, MusicTokenProvider
is a typealias
for a type that needs to be a subclass of MusicUserTokenProvider
, which conforms to the MusicDeveloperTokenProvider
protocol:
public typealias MusicTokenProvider = MusicUserTokenProvider & MusicDeveloperTokenProvider
Another example of combining is when we want our struct to conform to Codable
. If we’re creating a custom structure in the MusicKit framework, we can make it conform to MusicItem
and Codable
by providing a typealias
:
public typealias MusicCodableItem = MusicItem & Codable
Here, Codable
is a typealias
too!
We go through its declaration:
typealias Codable = Decodable & Encodable
Then use it, like so:
public struct UserMusicItem: MusicCodableItem { // MusicItem requirements // Codable requirements }
We can also separate the protocol conformances into different extensions for better clarity:
public struct UserMusicItem {} extension UserMusicItem: MusicItem { // MusicItem requirements } extension UserMusicItem: Decodable { // Decodable requirements } extension UserMusicItem: Encodable { // Decodable requirements }
It is up to you how to use typealias
in your codebase to maintain a balance between clarity and usefulness.
A similar example is conforming a type to Decodable
and ExpressibleByBooleanLiteral
:
typealias DecodableBooleanLiteral = Decodable & ExpressibleByBooleanLiteral
typealias
with cautionNow that you have a better understanding of how typealias
can make your codebase more readable, it may be tempting to use this function everywhere. However, there can be disadvantages to using typealias
indiscriminately.
For example, you will personally be familiar with the alias name that you give to specific types on a given project. But, issues could arise when an entire team of developers is working on a project that uses typealias
, or when a new member joins the team.
Even worse, some alias could confuse other developers. For example, let’s say use a generic typealias
for a completion handler:
typealias Completion = (String?, AnyObject?) -> ()
It may not initially be clear to other developers what Completion
does at first glance.
Let’s say you rename it to StringCompletion
:
typealias StringCompletion = (String?, AnyObject?) -> ()
This is better, but someone new to the codebase would still need to check to see the parameters.
It may be best to exercise caution when adding typealias
to your codebase. Try to only where it is specifically needed and where it makes the most sense.
In this article, we looked at basic and advanced examples of the typealias
function in Swift. typealias
can be useful for reducing verbosity and complexity and improving readability and clarity. typealias
is especially powerful when working with complex closure types and those conforming to multiple protocols.
However, despite its many advantages, it’s best not to introduce typealias
everywhere. If your colleagues have to look up the actual type for each typealias
, this will waste valuable time in context switching and will defeat the purpose of typealias
in the first place.
To learn more about the typealias
in Swift, see the official docs.
Install LogRocket via npm or script tag. LogRocket.init()
must be called client-side, not
server-side
$ npm i --save logrocket // Code: import LogRocket from 'logrocket'; LogRocket.init('app/id');
// Add to your HTML: <script src="https://cdn.lr-ingest.com/LogRocket.min.js"></script> <script>window.LogRocket && window.LogRocket.init('app/id');</script>
Would you be interested in joining LogRocket's developer community?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up nowLearn how to manage memory leaks in Rust, avoid unsafe behavior, and use tools like weak references to ensure efficient programs.
Bypass anti-bot measures in Node.js with curl-impersonate. Learn how it mimics browsers to overcome bot detection for web scraping.
Handle frontend data discrepancies with eventual consistency using WebSockets, Docker Compose, and practical code examples.
Efficient initializing is crucial to smooth-running websites. One way to optimize that process is through lazy initialization in Rust 1.80.