I posted this issue on the Feedback Assistant at Apple... but this really seems to be on Swift's part.
// MARK: - Models
public struct Donut {
public var flavor: String
public var isGlutenFree: Bool
public var isVegan: Bool
}
// MARK: - Endpoint Protocol
public protocol Endpoint {
associatedtype Result
}
extension Endpoint {
public typealias donuts = MyEndpoints.GetDonuts
}
// MARK: - Endpoints
public enum MyEndpoints {
public struct GetDonuts: Endpoint {
public typealias Result = [Donut]
var glutenFree: Bool = false
var vegan: Bool = false
public init(glutenFree: Bool = false, vegan: Bool = false) {
self.glutenFree = glutenFree
self.vegan = vegan
}
}
}
// MARK: - Client Protocol
public protocol ClientProtocol {
func get<T: Endpoint>(_ endpoint: T) async throws -> T.Result
}
// MARK: - Example
func someExample(_ client: ClientProtocol) async throws {
// Using non-typealias syntax works fine
let result0 = try await client.get(MyEndpoints.GetDonuts(glutenFree: true))
// result0 is of type Array<Donut> as expected
// Using typelias `donuts` in protocol Endpoint extension
let result1 = try await client.get(.donuts())
// doesn't work compile
}
Why would I expose my endpoints like this ?
Because it's a nice syntax,
- autocompletion of optional values is lovely with Xcode 14 beta
- autocompletion of available typealiases exists as well ...
Nothing prevents me to write the typealias and the type alias is correct.
1 Like
It doesn't work because .donuts does not return an instance of Endpoint. You have two options that I know of:
- Write
Endpoint.donuts.
- Write the boilerplate to forward the
GetDonuts initializer, which is really what you want, not a typealias. There was a big thread about making this unnecessary, but it didn't go anywhere.
But donuts should be equal to MyEndpoints.GetDonuts in my opinion, its a type alias it's like replacing it in code. And MyEndpoints.GetDonuts is a struct that responds to protocol Endpoint
No, if you actually wanted a type alias, you would capitalize it. Instead, you're trying to forward an initializer along so that it can be used with static member lookup:
extension Endpoint where Self == MyEndpoints.GetDonuts {
static func donuts(glutenFree: Bool = false, vegan: Bool = false) -> Self {
.init(glutenFree: glutenFree, vegan: vegan)
}
}
I agree that it should be easier to write that sort of code, and I suspect that as more people come across the pain of the boilerplate, we'll at least get better tooling support for generating it.
Found it.