Kenan Nur
Kenan Nur

Reputation: 433

How can I solve "Generic parameter 'T' could not be inferred" in Swift

I have following structs and functions.

struct ApiResponse<TResponse: Codable>: Codable {
    var isSuccess: Bool
    var mainResponse: TResponse?
}

public struct SomeResponse: Codable {
    var someProperty: String
}

public func postAsync<TRequest: Codable, TResponse: Codable>(route: String, request: TRequest) async throws -> TResponse? {

    let body = try JsonEncoder().encode(request)
    let urlRequest = createUrlRequest(route: route, method: "POST", body: body)

    let (data, _) = try await URLSession.shared.data(for: urlRequest)
    let apiResponse = try JsonDecoder().decode(ApiResponse<TResponse>.self, from: data)
    return response.mainResponse
}

I want to call postAsync func like that but it says **Generic parameter 'TResponse' could not be inferred** How can I call this method? I tried different ways but not solve.

 - let res = await postAsync(route: "MyController/Get", request: someRequest) as? SomeResponse
 - let res: SomeResponse = await postAsync(route: "MyController/Get", request: someRequest)

Upvotes: 2

Views: 726

Answers (2)

Rob Napier
Rob Napier

Reputation: 299345

Your function doesn't return SomeResponse, it returns SomeResponse?, so what you meant here is:

let res = ... as SomeResponse? // Note `as`, not `as?`

or

let res: SomeResponse? = ...

I agree with EmilioPaleaz about how to improve the API, though I would recommend adding a default value, which gives the best of both worlds:

... request: TRequest, returning: TResponse.Type = TResponse.self) async throws -> ...

With this, when the return type is known, you can omit it.

Upvotes: 3

EmilioPelaez
EmilioPelaez

Reputation: 19882

I'm not sure why your attempted solutions failed, maybe they don't work with the async/await feature.

That said, while in general it's possible to use implicit generics, the more common practice in Swift is to include the type as one of the arguments, instead of keeping it implicit. That's the way it's done in classes like JSONDecoder.

I would recommend changing your function signature to:

public func postAsync<TRequest: Codable, TResponse: Codable>(route: String, request: TRequest, receive: TResponse.Type) async throws -> TResponse? {

And calling it like this:

let res = await postAsync(route: "MyController/Get", request: someRequest, receive: SomeResponse.self)

Upvotes: 2

Related Questions