Ran into something curious (to me) today. This compiles as expected:
let opts = ["abc", "de", nil]
let a = opts
.compactMap { $0 }
.filter { $0.count > 2 }
// OK; `a` is a `[String]`
But this also compiles, even though the parameter into filter’s closure is non-optional: (EDIT: oops, I was mistaken here! $0 in the filter is a String?.)
let b = opts
.compactMap { $0 }
.filter { $0?.count ?? 0 > 2 }
// OK (!); `b` is a `[String?]`
Binding the result of the compactMap and then applying the filter to that, though, won’t compile:
let cPart1 = opts
.compactMap { $0 }
// `cPart1` is a `[String]`
let cPart2 = cPart1
.filter { $0?.count ?? 0 > 2 }
// err: Cannot use optional chaining on non-optional value of type 'String'
Is b a compiler bug? An expected limitation of the type-checker? An intended feature?
opts
.compactMap { $0 }
.compactMap { $0 as String }
.filter { $0?.count ?? 0 > 2 } // Cannot use optional chaining on non-optional value of type 'String'
opts
.compactMap(\.self)
.compactMap(\String.self)
.filter { $0?.count ?? 0 > 2 } // Cannot use optional chaining on non-optional value of type 'String'