What I want to achieve:
CustomView()
.doSomething() // ← should only be available on CustomView
.doSomethingElse() // ← should only be available on CustomView
AnyOtherView()
.doSomething() // ← should not compile
Pretty much like SwiftUI's Text implementation has that exact functionality:
What I tried
struct CustomView: View {
...
}
extension CustomView {
func doSomething() -> some CustomView {
self.environment(\.someKey, someValue)
}
func doSomethingElse() -> some CustomView {
self.environment(\.someOtherKey, someOtherValue)
}
}
I get the following error: "An 'opaque' type must specify only 'Any', 'AnyObject', protocols, and/or a base class".
What I also tried:
extension CustomView {
func doSomething() -> CustomView {
self.environment(\.someKey, someValue)
}
func doSomethingElse() -> CustomView {
self.environment(\.someOtherKey, someOtherValue)
}
}
I get the following error: Cannot convert return expression of type 'some View' to return type 'CustomView'. Xcode provides the following fix:
extension CustomView {
func doSomething -> CustomView {
self.environment(\.someKey, someValue) as! CustomView
}
}
But force casting does not really look like a great solution.
How can I fix this?
I only want to extend CustomView. I don't want to extend View and return some View because that would expose functionality to all views (which is not what I want).
If I extend CustomView and simply return some View, then I cannot use both functions at the same time.
Edit: Why do I want to achieve that?
I am building up a Swift Package to provide CustomView to multiple projects.
And to make CustomView easy to use I wanted to make it configurable with view modifiers instead of a simple initializer.
I could use my provided CustomView like that:
CustomView(value1: someValue, value2: someOtherValue)
... but I wanted to make it more SwiftUI-Like in the way of optional view modifiers like that:
CustomView()
.value1(someValue)
.value2(someOtherValue)
That would look nice if I needed other view modifiers on that view like tint(...) or fixedSize(), etc. Much like you would configure Text, which you customize with view modifiers instead of the initializer, since customizing is optional.

As others have pointed out, you cannot pipe any modifier in your functions that have a return type other than your
CustomViewWith that said, you can do something like:
And use it as needed:
But you cannot use any other modifier that erases your type. To reach your desired behavior, all the changes done in your functions/modifiers must be done only on properties accessible by your struct directly and have a return value that you guarantees is your view's type