In Swift, you can specify a union type using an enum. For example:
enum IntOrString {
case int(Int)
case string(String)
}
Now I want to write a property wrapper, which I can apply to properties of a type from my union type. However, I don't want to expose the enum I use behind the scenes. Instead, a user of my property wrapper should be able to apply it to a String or Int property directly.
One approach would work as follows.
@propertyWrapper
struct Managed<T> {
private var storage: IntOrString
var wrappedValue: T {
get {
switch storage {
case .int(let int):
return int as! T
case .string(let string):
return string as! T
}
}
set {
if T.self == Int.self {
storage = .int(newValue as! Int)
} else if T.self == String.self {
storage = .string(newValue as! String)
} else {
fatalError("Property has an illegal type")
}
}
}
}
Unfortunately however, I lose static type safety with this approach, as a user can now apply Managed to a property which is neither Int nor String and would only get a runtime error, once he tries to set the property.
struct Foo {
@Managed var bar: Double
}
let foo = Foo(bar: 0) // fatal error
As far as I'm aware, I cannot specify a type constraint on T which only allows for T to be Int or String.
So is there any way in Swift to get static type safety on union types in this scenario?
If not, are there more elegant workarounds to my approach?
Actually you can with a helper protocol
With this solution the property wrapper can be reduced to
Then
bardeclared asDoubleraises this compiler error