This introduces some interesting use cases with generics and tuples. This could allow, for instance, a generic type to wrap a poorly-typed dictionary with its expected key-value mapping expressed as a tuple. Combined with StoredPropertyIterable and the ability to extract the names of key paths, you could write a wrapper that checks the contents of a dictionary on construction, and provides strongly-typed access to its contents:
struct WellTypedDictionary<Schema> {
var dictionary: [String: Any]
init?(_ dictionary: [String: Any]) {
for key in keys(Schema.self) {
guard
let value = dictionary[key.name],
type(of: value) == key.valueType
else {
return nil
}
}
self.dictionary = dictionary
}
subscript<U>(keyPathMember: WritableKeyPath<Schema, U>) -> U {
get {
return dictionary[keyPathMember.name] as! U
}
set {
dictionary[keyPathMember.name] = newValue
}
}
}
let record = ["name": "Julius", "job": "Caesar", age: 55, "leastFavoriteDish": "et-tu-ffée"]
guard let checkedRecord = WellTypedDictionary<(name: String, age: Int)>(record) else {
print("invalid record")
return
}
print("\(checkedRecord.name) is \(checkedRecord.age)")