Have you ever wanted to return some kind of value from a function but didn’t want to expose exactly what type it is? Like telling the compiler, I’ll tell you it conforms to a protocol, but you don’t need to know the concrete type. Just trust me, it’ll work. Well, that’s what opaque types are for. Let’s break it down together.
So What Is an Opaque Type?
An opaque type in Swift is a return type that hides the concrete type behind a protocol. You’ve seen this syntax before:
func makeButton() -> some View {
Text("Tap me!")
}
That some View
is the magic. Instead of returning a Text
, or a Button
, or a ZStack
, we say, I’m returning some type that conforms to View
, you don’t need to know which one. That’s the whole idea.
Why Not Just Return View
?
Let’s try that:
func makeButton() -> View {
Text("Tap me!")
}
This will throw a compiler error.
“Use of protocol ‘View’ as a type must be written ‘any View’; this will be an error in a future Swift language mode.”
“Type ‘any View’ cannot conform to ‘View’”
That’s the problem. Most SwiftUI protocols (like View
, Shape
, Animatable
, etc.) have associated types and Swift can’t just erase them like that. You can’t return a protocol with associated types directly, but you can return some type that conforms to that protocol. Hence:
func makeButton() -> some View
So What Does some View
Actually Mean?
It means, This function returns a specific, single type that conforms to View
but I’m not telling you what type that is. The type is opaque to the caller, but Swift still knows what it is under the hood and gives you all the safety. It’s like giving someone a sealed box and saying, What’s inside is definitely a toy car. You don’t need to know the brand.
A Real Example:
func primaryButton(label: String) -> some View {
Text(label)
.padding()
.foregroundStyle(.white)
.background(.blue)
.clipShape(Capsule())
}
You don’t need to know the internals. All you care about is that it returns some View and Swift guarantees it works.
What if I Return Different Types?
You can’t do this:
func errorView(hasError: Bool) -> some View {
if hasError {
Text("An error occurred")
} else {
Image(systemName: "checkmark")
}
}
You will get a compiler error like:
“Branches have mismatching types ‘Text’ and ‘Image’”
Why? Because Text
and Image
are different concrete types, even though both conform to View
. And some View
means “always returns one specific type.”
How to Fix It
Wrap them in something like AnyView
:
func errorView(hasError: Bool) -> some View {
if hasError {
AnyView(Text("An error occurred"))
} else {
AnyView(Image(systemName: "checkmark"))
}
}
Note that AnyView erases the type, but it has a performance cost so use it only when needed.
Opaque Return Types with Custom Protocols
You can use some T
with your own protocols too. This works as long as the function always returns one concrete type.
protocol Weapon {
func damage() -> Int
}
struct Sword: Weapon {
func damage() -> Int { 20 }
}
struct Bow: Weapon {
func damage() -> Int { 12 }
}
func equipSword() -> some Weapon {
Sword()
}
Although this won’t compile:
func equipRandomWeapon() -> some Weapon {
Bool.random() ? Sword() : Bow() // returns two types
}
You are going to see an error like:
Result values in ‘? :’ expression have mismatching types ‘Sword’ and ‘Bow’
some
vs any
: Know the Difference
Use some
when:
- You want to preserve performance
- You always return the same concrete type
- You’re working with SwiftUI or associated-type protocols
Use any
when:
- You want flexibility over performance
- You need to return different conforming types
- You’re ok with type-erased abstraction
Opaque types give Swift a rare blend of type safety, performance, and flexibility all without exposing internals. Whether you’re writing SwiftUI components, generic logic, or DSLs, you’ll run into some
often. Now that you know how it works, you’ll never look at some View
the same again 😉. That was all for this one i will see you in the next one 🙂
Oh and if you want to dig deeper check out a more detailed version of this topic here: https://docs.swift.org/swift-book/documentation/the-swift-programming-language/opaquetypes/