I'm using Apollo Client to autogenerate graphql types and queries in Xcode but have run into an issue I'm not sure how to best solve. TLDR is how can I allow one struct to be used as an argument for a function that accepts another type with the same structure?
Apollo generates a struct for me called "SizeInput" as follows:
struct SizeInput: GraphQLMapConvertible {
public var graphQLMap: GraphQLMap
public init(cm: Double) {
graphQLMap = ["cm": cm]
}
public var cm: Double {
get {
return graphQLMap["cm"] as! Double
}
set {
graphQLMap.updateValue(newValue, forKey: "cm")
}
}
}
(BTW - GraphQLMap
is a typealias for [String : JSONEncodable?]
)
I created a Size
struct for use in my code. I don't want to use the SizeInput
in my code to keep the back-end separate from my app code so things don't break if the back-end or app changes.
struct Size {
let cm: Double
}
I need to run an apollo query that takes SizeInput
as an argument, which I want to populate from my Size
variable populated from a picker. While I know I can create a new SizeInput
from Size
, I'd love to just pass Size
into the query because they're essentially the same, just two different types. As of now, XCode obviously complains Cannot convert value of type 'Size' to expected argument type 'SizeInput'
The kicker is that I can't (don't want to) change the Apollo function because that's autogenerated. So my ideal solution is to typecast Size
to SizeInput
in some fashion, but XCode complains if I just try to do let sizeInput = size as? SizeInput
where size
is a Size
.
Assuming I can't modify the function accepting the argument and I can't modify SizeInput
because both are autogenerated, how can I modify Size
so it can be used as a SizeInput
argument?
Size
and SizeInput
according to your post are two different types and therefore can't be type aliased in the manner you are thinking.
Swift's Declarations reference says the following about typealias
:
A type alias declaration introduces a named alias of an existing type into your program. [...] After a type alias is declared, the aliased name can be used instead of the existing type everywhere in your program. [...] Type aliases do not create new types; they simply allow a name to refer to an existing type.
... but that's not what you want. Size
and SizeInput
are similar contractually in that they have a cm: Double
property, but are structurally different under the hood and can't be used interchangeably.
You're going to need to make some trade-offs with whatever solution you choose. I see at least the following options.
Size
) and use that. Then translate your Size
to SizeInput
. Codegen could be used.Size
to SizeInput
on the Size
type itself and then use that at your GraphQL call-sites. Codegen could be used here too.extension Size {
func asSizeInput() -> SizeInput {
return SizeInput(cm: cm)
}
}
Size
instance's cm
property into the constructor of SizeInput
, then you're not writing any extra code. Here's some pseudo code:let size = Size(cm: 100)
let query = SizeInputGraphQLQuery(sizeInput: size.cm)
For my $, I'd opt for writing as little extra code as possible.
YMMV