Search code examples
swiftswiftuiclosuresopaque-types

Why can't I return a closure that returns a view from a Swift function declared as "-> () -> some View"?


struct NavLinkLabel: View {
    var text: String
    var body: some View {
        HStack {
            Text(text)
            Spacer()
            Image(systemName: "chevron.right")
        }
        .padding()
        .border(.bar)
    }
}

func lbl(_ text: String) -> () -> some View {
    return {
        NavLinkLabel(text: text) //ERROR
    }
}

This gives me an error on the marked line:

Cannot convert value of type 'NavLinkLabel' to closure result type 'some View'

This is despite the fact that NavLinkLabel conforms to the View protocol.

If I replace the offending line with NavLinkLabel(text: text).body, I get this:

Cannot convert value of type 'some View' (type of 'NavLinkLabel.body') to closure result type 'some View' (result of 'lbl')

Why can't it convert a conforming type, or an even an opaque type, to an opaque type of the same protocol? I don't doubt there's a better way to do this anyway, but I'm just experimenting and wondering why this doesn't work.


Solution

  • If you really need to return a closure (ie, actually a builder) then the simplest (and actually the one) variant is just to declare what is known concrete type (as we know what's returned), ie

    func lbl(_ text: String) -> () -> NavLinkLabel {     // << here !!
        return {
            NavLinkLabel(text: text)
        }
    }
    

    Otherwise just return NavLinkLabel(text: text) directly, because the some support is limited in swift (at v5.6 time). It is only

    'some' types are only implemented for the declared type of properties and subscripts and the return type of functions

    means direct return type, not return of returned closure - it is out of scope.