Swift Generics Error: Cannot Convert Value of Type 'Type<T>' to Expected Argument Type 'Type<_>'

Swift generics error: Cannot convert value of type 'Type T ' to expected argument type 'Type _ '

You are using a non-generic concrete type MyModel in a generic function, that doesn't work.

You could do something like this

class Test {
func test<T: MyProcotol>(item: T, completion: (Result<T>) -> Void) {
let result : Result<T> = .success(value: item)
completion(result)
}
}

Cannot convert value of type 'T?' to expected argument type 'T?'

You need to use an associatedtype in your protocol so all functions/variables in the protocol uses the same type because otherwise each function with a <T> will be using a different type

Example (simplified

protocol PostDataProviderProtocol{
associatedtype T

func getItemAt(index:Int)-> T?
func replaceItemAt(index:Int, item:T?)
}

Then in your class you can use it as

class BaseDataProvider<SomeType> {
internal var _itemsPerPage:Int = 0
internal var _page:Int = 0
internal var _endpoint:String = ""
internal var cachedData:[SomeType?] = []
}

extension BaseDataProvider: PostDataProviderProtocol {
typealias T = SomeType

func hasNext() -> Bool {
true
}

func getItemAt(index: Int) -> T? {
self.cachedData[index]
}

func getItems() -> [T] {
return self.cachedData as! [T]
}

}

Cannot convert type value of type Observable Store to expected argument type Observable Store?

You have to wrap the object into an Optional:
StoreMock(state: stateSubject, store: storeSubject.map(Optional.some))

Just one call will fix this.

Swift: cannot convert value of type 'SomeType T ' to expected argument type 'SomeType _ '

The following code worked for me.

struct PageData<T> {
let item: T
let pageNumber: Int
}

protocol PagedServiceProvider: class {
associatedtype T
var pageData: PageData<T>? { get set }
func fetchPage(page: Int, completion: @escaping (PageData<T>?) -> Void)
}

class TestPagedServiceProvider: PagedServiceProvider {

var pageData: PageData<String>?

func fetchPage(page: Int, completion: @escaping (PageData<String>?) -> Void) {
completion(pageData)
}

}

Cannot convert value of type 'Codable' (aka 'Decodable & Encodable') to expected argument type 'T.Type'

What you need is a generic method:

private func parseJson<T: Decodable>(data: Data, type: T.Type) -> T? {
do {
return try JSONDecoder().decode(type.self, from: data)
} catch {
print("JSON decode error:", error)
return nil
}
}

You can also omit the type and explicitly set the type of the resulting object:

private func parseJson<T: Decodable>(data: Data) -> T? {
do {
return try JSONDecoder().decode(T.self, from: data)
} catch {
print("JSON decode error:", error)
return nil
}
}

Playground testing:

struct User: Codable {
let id: Int
let name: String
}
let user: User = .init(id: 2, name: "abc")
let userData = try! JSONEncoder().encode(user)

let decodedUser: User = parseJson(data: userData)!
decodedUser.name // "abc"

Note: I am returning optional types but you should definitely make your methods throw and return a non optional as you can see below where I am extending Data:

extension Data {
func decodedObject<T: Decodable>() throws -> T {
try JSONDecoder().decode(T.self, from: self)
}
}


do {
let decodedUser: User = try userData.decodedObject()
print(decodedUser.name) // "abc"
} catch {
print(error)
}

Swift Generics: Cannot convert value of type to expected argument type

Swift 4.1 Update

This is a bug that was fixed in this pull request, which will make it into the release of Swift 4.1. Your code now compiles as expected in a 4.1 snapshot.


Pre Swift 4.1

This just looks like you're just stretching the compiler too far.

  • It can deal with conversions from arrays of sub-typed elements to arrays of super-typed elements, e.g [A] to [SomeProtocol] – this is covariance. It's worth noting that arrays have always been an edge case here, as arbitrary generics are invariant. Certain collections, such as Array, just get special treatment from the compiler allowing for covariance.

  • It can deal with conversions of functions with super-typed parameters to functions with sub-typed parameters, e.g (SomeProtocol) -> Void to (A) -> Void – this is contravariance.

However it appears that it currently cannot do both in one go (but really it should be able to; feel free to file a bug).

For what it's worth, this has nothing to do with generics, the following reproduces the same behaviour:

protocol SomeProtocol {}
class A : SomeProtocol {}

func f1(listener: (A) -> Void) {}
func f2(listener: ([A]) -> Void) {}
func f3(listener: () -> [SomeProtocol]) {}

func g() {

let l1: (SomeProtocol) -> Void = { _ in }
f1(listener: l1) // NO ERROR

let l2: ([SomeProtocol]) -> Void = { _ in }
f2(listener: l2)
// COMPILER ERROR: Cannot convert value of type '([SomeProtocol]) -> Void' to
// expected argument type '([A]) -> Void'

// it's the same story for function return types
let l3: () -> [A] = { [] }
f3(listener: l3)
// COMPILER ERROR: Cannot convert value of type '() -> [A]' to
// expected argument type '() -> [SomeProtocol]'
}

Until fixed, one solution in this case is to simply use a closure expression to act as a trampoline between the two function types:

// converting a ([SomeProtocol]) -> Void to a ([A]) -> Void.
// compiler infers closure expression to be of type ([A]) -> Void, and in the
// implementation, $0 gets implicitly converted from [A] to [SomeProtocol].
f2(listener: { l2($0) })

// converting a () -> [A] to a () -> [SomeProtocol].
// compiler infers closure expression to be of type () -> [SomeProtocol], and in the
// implementation, the result of l3 gets implicitly converted from [A] to [SomeProtocol]
f3(listener: { l3() })

And, applied to your code:

f2(ofType: A.self, listener: { l2($0) })

This works because the compiler infers the closure expression to be of type ([T]?) -> Void, which can be passed to f2. In the implementation of the closure, the compiler then performs an implicit conversion of $0 from [T]? to [SomeProtocol]?.

And, as Dominik is hinting at, this trampoline could also be done as an additional overload of f2:

func f2<T : SomeProtocol>(ofType type: T.Type, listener: ([SomeProtocol]?) -> Void) {
// pass a closure expression of type ([T]?) -> Void to the original f2, we then
// deal with the conversion from [T]? to [SomeProtocol]? in the closure.
// (and by "we", I mean the compiler, implicitly)
f2(ofType: type, listener: { (arr: [T]?) in listener(arr) })
}

Allowing you to once again call it as f2(ofType: A.self, listener: l2).

Swift: cannot convert value of type to expected argument type when setting up a selector

Your method takes a parameter, so try

self.performSelector(onMainThread: #selector(updateUIwithJsonResponse(json:)), with: json, waitUntilDone: true)

Cannot convert value of type 'MyEnum T.Type ' to expected argument type 'MyEnum _ '

The error occurs because NetworkResponse expects an instance of T, while the mock tries to provide the actual T.

So, you need to somehow provide an instance, however this cannot be generated by the mock as it doesn't have enough information about how to construct an instance.

I recommend injecting the success value from the outside, when creating the mock. You can do this either by making the mock class generic, or by making the Mode enum generic. Below is a sample implementation for the latter:

class MockUrlSessionProvider: ProviderProtocol {

// making the enum generic, to support injecting the success value
enum Mode<T> {
case success(T)
case empty
case fail
}

// need to have this as `Any` to cover all possible T generic arguments
private var mode: Any

// however the initializer can be very specific
init<T>(mode: Mode<T>) {
self.mode = mode
}

func request<T>(type: T.Type, service: ServiceProtocol, completion: @escaping (NetworkResponse<T>) -> Void) where T: Decodable {
// if the mock was not properly configured, do nothing
guard let mode = mode as? Mode<T> else { return }
// alternatively you force cast and have the unit test crash, this should help catching early configuration issues
// let mode = mode as! Mode<T>

switch mode {
case let .success(value): completion(NetworkResponse.success(value))
case .empty: completion(.failure(.noData))
case .fail: completion(.failure(.unknown("Error")))
}

}
}


Related Topics



Leave a reply



Submit