Get specific CodingKey for KeyPath

Viewed 2083

Consider the following object:

struct User: Codable {
    let id: Int
    let email: String
    let name: String
}

Is it posible to get a specific CodingKey for a given KeyPath?

let key = \User.name.codingKey  // would be equal to string: "name"
2 Answers

Using Swift 4, I don't think you can automatically retrieve a CodingKey from the corresponding KeyPath object but you can always hack your way around it ;)

For instance, in the same User type Swift source file, add the following extension:

fileprivate extension User {
    static func codingKey(for keyPath: PartialKeyPath<User>) -> CodingKey {
        switch keyPath {
        case \User.id:    return CodingKeys.id
        case \User.email: return CodingKeys.email
        case \User.name:  return CodingKeys.name
        default: fatalError("Unexpected User key path: \(keyPath)")
        }
    }
}

then implement the desired codingKey API in the constrained KeyPath superclass:

extension PartialKeyPath where Root == User {
    var codingKey: CodingKey {
        return User.codingKey(for: self)
    }
}

Finally, the usage follows closely your code:

let name: CodingKey = (\User.name).codingKey
print("\(name)") // prints "name"

This may be a somewhat tedious and error prone solution but, if you only need this capability for handful of types, it's perfectly doable in my opinion ;)

Caveats. This hack, of course, won't work for externally defined types given CodingKeys enum private visibility. (For instance, for all Codable types defined by the Swift Standard Library.)

I don't think you can convert property directly to the string but you can achieve similar thing using reflection, but you have to create an instance of the struct:

let user = User(id: 1, email: "sample@email.com", name: "just_name")
Mirror(reflecting: user).children.first?.label
Related