Swift extension - Constrained extension must be declared on the unspecialized generic type 'Array'

Viewed 5630

I have an API that returns a JSON array of objects. I've setup the structure to look as follows:

typealias MyModels = [MyModel]

struct MyModel: Codable {
    let field1: String
    let field2: String
    let mySubModel: SubModel?
    
    enum CodingKeys: String, CodingKey {
        case field1 = "Field1"
        case field2 = "Field2"
        case mySubModel = "MySubModel"
    }
}

struct SubModel: Codable {
    let subModelField1: String
    let subModelField2: String
    
    enum CodingKeys: String, CodingKey {
        case subModelField1 = "SubModelField1"
        case subModelField2 = "SubModelField2"
    }
}

What I want to do is add this extension, supplying a path var (the NetworkModel protocol provides some base functionality for API operations):

extension MyModels: NetworkModel {
    static var path = "the/endpoint/path"
}

I don't have any issues in other model/struct classes that I setup in this way when the base is an object or json key. However, since this one is different and simply is an array, I get this error when I put that extension in the class:

Constrained extension must be declared on the unspecialized generic type 'Array' with constraints specified by a 'where' clause

I've done some digging and tried a few things with a where clause on the extension, but I'm just a bit confused as to what it wants. I'm sure it's something simple, but any thoughts on this? If I need to go about it a different way with the typealias above, I'm fine with that. Thanks in advance!

2 Answers

The error is basically telling you to do this:

extension Array : NetworkModel where Element == MyModel {
    static var path = "the/endpoint/path"
}

You can't simply make an extension of [MyModel].

Although Sweeper answered the question appropriately based on the initial question, I wanted to provide an alternative approach, even if potentially slightly more complex. This can be accomplished by overriding the Decodable side of things and manually putting the models into a list:

struct MyModels: Codable {
    var modelList: [MyModel] = []

    public init(from decoder: Decoder) throws {
        var container = try decoder.unkeyedContainer()
        let metaType = (Account.self as Decodable.Type)

        while !container.isAtEnd {
            let subdecoder = try container.superDecoder()
            if let model = try metaType.init(from: subdecoder) as? MyModel {
                modelList.append(model)
            }
        }
    }
}

struct MyModel: Codable {
    let subModelField1: String
    let subModelField2: String

    enum CodingKeys: String, CodingKey {
        case subModelField1 = "SubModelField1"
        case subModelField2 = "SubModelField2"
    }
}

extension MyModels: NetworkModel {
    static var path = "the/endpoint/path"
}
Related