14

Is it possible to check if a variable is an optional, and what type is it wrapping?

It is possible to check if a variable is an specific optional:

let someString: String? = "oneString"
var anyThing: Any = someString

anyThing.dynamicType // Swift.Optional<Swift.String>
anyThing.dynamicType is Optional<String>.Type // true
anyThing.dynamicType is Optional<UIView>.Type // false

But is it possible to check agains any type of optional? Something like:

anyThing.dynamicType is Optional.Type // fails since T cant be inferred
// or 
anyThing.dynamicType is Optional<Any>.Type // false

And once knowing you have an optional, retrieve the type it is wrapping:

// hypothetical code 
anyThing.optionalType // returns String.Type
Maic López Sáenz
  • 10,385
  • 4
  • 44
  • 57
  • Anyway, you should not put `Optional` into `Any`. see: [How to unwrap an optional value from Any type?](http://stackoverflow.com/q/27989094/3804019) – rintaro Sep 18 '15 at 11:15
  • It may be a valid case, you could have a function that accepts `Any` and that behaves differently if it receives an `Optional`. – Maic López Sáenz Sep 25 '15 at 11:14

2 Answers2

9

Since a protocol can be created as means of a typeless Optional the same protocol can be used to provide access to the optional type. Example is in Swift 2, although it should work similarly in previous versions:

protocol OptionalProtocol {
    func wrappedType() -> Any.Type
}

extension Optional : OptionalProtocol {
    func wrappedType() -> Any.Type {
        return Wrapped.self
    }
}

let maybeInt: Any = Optional<Int>.Some(12)
let maybeString: Any = Optional<String>.Some("maybe")

if let optional = maybeInt as? OptionalProtocol {
    print(optional.wrappedType()) // Int
    optional.wrappedType() is Int.Type // true
}

if let optional = maybeString as? OptionalProtocol {
    print(optional.wrappedType()) // String
    optional.wrappedType() is String.Type // true
}

The protocol can even be used to check and unwrap the contained optional value

Community
  • 1
  • 1
Maic López Sáenz
  • 10,385
  • 4
  • 44
  • 57
7

With Swift2.0:

let someString: String? = "oneString"
var anyThing: Any = someString

// is `Optional`
Mirror(reflecting: anyThing).displayStyle == .Optional // -> true

But extracting wrapped type is not so easy.

You could:

anyThing.dynamicType // -> Optional<String>.Type (as Any.Type)
Mirror(reflecting: anyThing).subjectType // -> Optional<String>.Type (as Any.Type)

But I don't know how to extract String.Type from Optional<String>.Type wrapped with Any.Type

rintaro
  • 51,423
  • 14
  • 131
  • 139
  • So far its seems like its currently impossible to extract the `String.Type` out of `Optional.self`. However it is possible to extend the `Optional` enum to provide a method that returns the wrapped type, and use any instance to access it. – Maic López Sáenz Sep 25 '15 at 11:34
  • Like [this](http://stackoverflow.com/a/28964069/3804019)? When you have `Optional.self` as `Optional.Type`, you can. But I thinks it's impossible for `Any.Type`. – rintaro Sep 25 '15 at 11:49
  • You just taught me how to do it: if you have `let anyType: Any.Type = Array.self`, then just cast it back: `(anyType as! Array.Type).Element.self` will return `String.Type` :) – Maic López Sáenz Sep 25 '15 at 12:09