Swift typealias: What is it and when to use it
Table of Contents
What is typealias
A type alias declaration[1] introduces a named alias of an existing type into your app. You can think of it as defining a nickname for an existing type.
You can easily support sarunw.com by checking out this sponsor.
AI Grammar: Correct grammar, spell check, check punctuation, and parphrase.
How to declare a typealias
Type alias declarations are declared using the typealias
keyword and have the following form:
typealias name = existing type
Since typealias
is just a nickname of the existing type, you can use it interchangeably everywhere in your app.
Here is an example of declaring a type alias of Int
as i
.
typealias i = Int
let one: Int = 1
let alsoOne: i = one
print(alsoOne)
// 1
We can assign Int
to the new i
type without any problem.
What is the purpose of typealias
We use typealias to introduce a new semantic type out of the existing one.
Type aliases don't create new types. They simply allow a name to refer to an existing type.
We use this to give a more meaningful name to convey a clearer message to the reader. Let's take a look at the TimeInterval
type.
In Foundation
, it declares a TimeInterval
type alias for a type Double
.
/// A number of seconds.
public typealias TimeInterval = Double
TimeInterval
gives more context to the type Double
. Based on the comment, we know that the double represents the number of seconds. This gives more context to our methods and code.
Compare these two identical methods. You can tell at a glance that the first one expected a number of seconds. The later function might leave you wondering what argument the method expects; it can be seconds, minutes, or hours.
extension NSDate {
open func addingTimeInterval(_ ti: TimeInterval) -> Self
open func addingTimeInterval(_ ti: Double) -> Self
}
You can see that even the above example from Foundation
is still based on some preference and judgment. To know that TimeInterval
is in seconds, you have to check out its document at least once.
You can just document this in the method argument without introducing a new type alias.
If you look into addingTimeInterval
, it already mentioned that ti
is in seconds.
/// Creates a new date value by adding a time interval to this date.
/// - Parameter ti: The value to add, in seconds.
/// - Returns: A new date value calculated by adding a time interval to this date.
open func addingTimeInterval(_ ti: Double) -> Self
Introducing a new type means everyone has to check out its definition to see what it is. Since there are many date functions in the framework, the cost of introducing a new type alias might benefit users of the framework in the long run. You can understand at a glance without looking into a document that argument is expecting seconds.
This is the trade-off you have to consider before introducing a new type.
When should I use typealias
In general, a typealias function is to repurpose an existing type by giving a new name to it.
With great power comes great responsibility.
Like every language feature, you should know when to and shouldn't use it. Use a typealias too much, and you might confuse your teammate or your future self. You have to find a balance for yourself.
I can't tell you when you should use it. The best I can do is show you some scenarios. So, you can judge for yourself when and where you want to introduce new type alias.
Domain-specific type
If you have a domain-specific module, you might want to declare a new name to an existing type to convey a clearer message for your domain. We have already seen this in the previous example with TimeInterval
.
Here is an example where typealias is used for a Mathematic domain.
extension Float : BinaryFloatingPoint {
/// A type that can represent the absolute value of any possible value of the
/// conforming type.
public typealias Magnitude = Float
/// A type that can represent any written exponent.
public typealias Exponent = Int
}
And another example from CoreLocation
.
/// Type used to represent a latitude or longitude coordinate in degrees under the WGS 84 reference
/// frame. The degree can be positive (North and East) or negative (South and West).
public typealias CLLocationDegrees = Double
/// Type used to represent a distance in meters.
public typealias CLLocationDistance = Double
Anonymous types/functions
By anonymous[2], I mean a function/type without a name. Closure and Tuple fall into this category.
Closure
Here are some examples of closure you usually see in methods with a callback.
() -> Void
(Bool) -> Void
Just like a built-in type, you can make typealias over a closure.
/// Type used to represent a callback when operation is completed or failed.
typealias CompletionCallback = (Bool) -> Void
typealias VoidCallback = () -> Void
This makes the purpose of a callback clearer, and I think it greatly improves readability. Here is a comparison between the two versions.
class func animate(
withDuration duration: TimeInterval,
animations: @escaping () -> Void,
completion: ((Bool) -> Void)? = nil)
class func animate(
withDuration duration: TimeInterval,
animations: @escaping VoidCallback,
completion: CompletionCallback? = nil)
I have a hard time understanding closure in a method signature, especially with an optional closure. Type alias really helps me in this area.
Tuple
If you use Tuple, you can also give it a name that also improves readability. But if you need to do this for your tuple, you might consider promoting your tuple to a proper struct or class.
typealias Coordinate = (Int, Int)
let a: (Int, Int) = (1, 2)
let b: Coordinate = (1, 2)
Shorter name for associatedtype
Inside a protocol declaration, a type alias can give a shorter name to associatedtype
.
Here is an example from the Sequence
protocol, which exposes the underlying Element
type from IteratorProtocol
for easy access.
public protocol IteratorProtocol {
/// The type of element traversed by the iterator.
associatedtype Element
}
protocol Sequence {
associatedtype Iterator: IteratorProtocol
typealias Element = Iterator.Element
}
We can easily refer to Element
directly from Sequence
.
func sum<T: Sequence>(_ sequence: T) -> Int where T.Element == Int {
// ...
}
Shorter name for nested types
You can use a type alias to create a shorter name for a nested type.
For example:
public enum Unicode {
public enum UTF8 : Sendable { ... }
public enum UTF16 : Sendable { ... }
public enum UTF32 : Sendable { ... }
}
public typealias UTF8 = Unicode.UTF8
public typealias UTF16 = Unicode.UTF16
public typealias UTF32 = Unicode.UTF32
Group multiple protocols
You can use a type alias to combine multiple protocols into one.
For example, the Codable
protocol includes both Decodable
and Encodable
together.
public typealias Codable = Decodable & Encodable
Generic types
A type alias can use to provide concrete types for some or all of the generic parameters of the existing type.
For example, I declare a new Result
type for my API call. In this case, I provide a concrete type of Error
parameter of Result<Success, Failure>
.
enum APIError: Error {}
typealias APIResult<Success> = Result<Success, APIError>
Here is another example where I provide concrete types for all of the generic parameters.
typealias NoContent = Result<Void, APIError>
You can easily support sarunw.com by checking out this sponsor.
AI Grammar: Correct grammar, spell check, check punctuation, and parphrase.
Conclusion
A type alias is a powerful tool. It gives you the ability to give a nickname or synonym to an existing type, giving a more meaningful name to convey a clearer message to the reader.
Everyone has to check out for a definition of the type when they first encounter the type. This might cause unnecessary overhead and confusion. But if you use the new type many places in your code, the benefit might outweigh the overhead.
This is the thing that you have to consider when adopting a type alias.
A declaration introduces a new name or construct into your program. For example, you use declarations to introduce functions and methods, to introduce variables and constants, and to define enumeration, structure, class, and protocol types. You can also use a declaration to extend the behavior of an existing named type and to import symbols into your program that are declared elsewhere. https://docs.swift.org/swift-book/ReferenceManual/Declarations.html ↩︎
I borrow the name from Anonymous function. ↩︎
Read more article about Swift or see all available topic
Enjoy the read?
If you enjoy this article, you can subscribe to the weekly newsletter.
Every Friday, you'll get a quick recap of all articles and tips posted on this site. No strings attached. Unsubscribe anytime.
Feel free to follow me on Twitter and ask your questions related to this post. Thanks for reading and see you next time.
If you enjoy my writing, please check out my Patreon https://www.patreon.com/sarunw and become my supporter. Sharing the article is also greatly appreciated.
Become a patron Buy me a coffee Tweet ShareHow to use Proxyman with Flutter
If you use Proxyman with a Flutter app, you might not see any traffic from your Flutter Project. Here is how to fix it.
How to fix "Unable to boot the iOS simulator" error
There might be several reasons that cause this error. I will share the solution that works for me.