2

I would like to extend SwiftUI Binding when its value is any optional type. Is it possible

extension Binding where Value == Optional {
    func filter(_ predicate: @escaping (Value) -> Bool) -> Binding<Value> {
        Binding<Value>(
            get: {
                if predicate(wrappedValue) { return nil }
                return wrappedValue
            },
            set: {
                wrappedValue = $0
            }
        )
    }
}

It works if I use some concrete type like Error? But I want to have more general solution.

George
  • 25,988
  • 10
  • 79
  • 133
Michał Ziobro
  • 10,759
  • 11
  • 88
  • 143
  • If `Value` is an optional for `predicate`, why isn't the return type (`Bool`) also optional? What would you do to convert an optional value to a non-optional boolean? – George Aug 10 '21 at 15:17
  • for value == nil it will return true as this values aren't filtered and are allowed by binding – Michał Ziobro Aug 10 '21 at 16:19

1 Answers1

3

You can create a generic T where T? == Value. This means that Value is an optional (and T is the wrapped value of the optional, even though we don't need this type directly).

Code:

extension Binding {
    func filter<T>(_ predicate: @escaping (Value) -> Bool) -> Binding<Value> where T? == Value {
        Binding<Value>(
            get: {
                if predicate(wrappedValue) { return nil }
                return wrappedValue
            },
            set: {
                wrappedValue = $0
            }
        )
    }
}
George
  • 25,988
  • 10
  • 79
  • 133
  • you don't use `T` type in your func – Phil Dukhov Aug 10 '21 at 15:55
  • @Philip No, but that doesn't matter. You could effectively substitute the `Value`s for `T?`, but this is much cleaner, and also necessary because it tells the compiler that this method is _only_ available when `Value` is optional. – George Aug 10 '21 at 16:02