In our app we have an enum defined that covers all the back end endpoints that can be hit by the app...
enum Route {
case todo(TodoRoute)
case event(EventRoute)
case userDetails
enum TodoRoute {
case create
case delete(Todo)
}
case EventRoute {
case list
case edit(Event)
}
}
These get translated into the individual endpoints and parameters and so on.
So we have a couple of functions on our ApiClient like this that eventually make the network call...
public func request<A: Decodable>(
_ route: Route,
as: A.Type
) async throws -> A {
let (data, _) = try await self.request(route)
do {
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601
return try decoder.decode(A.self, from: data)
} catch {
throw error
}
}
public func request<A: Decodable>(
_ route: Route
) async throws -> A {
let (data, _) = try await self.request(route)
do {
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601
return try decoder.decode(A.self, from: data)
} catch {
throw error
}
}
As you can see, these decode the returned data into a particular generic type.
So at the call site it looks like one of these...
// 1.
let result = try await apiClient.request(.userDetails, as: UserDetails.self)
// 2.
let result: EventList = try await apiClient.request(.event(.list))
These work but I'm trying to find a way to embed the type to be decoded into the function call itself.
Each endpoint we call will only return one type of JSON so there is a 1:1 mapping between our Route
cases and the type returned by the function. So rather than having to explicitly define both the route AND the type in the function it should be possible to only provide the route and have the type inferred. Something like this...
let result = try await apiClient.request(.event(.list))
And have the type of result
inferred from the Route
passed into the function.
Perhaps this just isn't possible?
I was thinking of having a function on the route like route.resourceType
or something? So the function can infer what T is from that? Or something?
Hmm... as I type I'm thinking that isn't possible?
Is it possible to make such and type inference work?
CodePudding user response:
Just to make it clear this is answered.
As @RobNapier pointed out. Inferring a type based on a value is not something that is a feature within Swift. Although it does exist in other languages. It’s not one to wait for in Swift.