Fix for DecodingError "Expected to decode Double but found Int instead."#22
Fix for DecodingError "Expected to decode Double but found Int instead."#22andrewash wants to merge 1 commit intotattn:masterfrom
Conversation
Int literals cannot be cast as a Double using `as?` so `Double(<Int>)` must be used instead. JSON has only one Number type, and allows "5" to be considered a Double, not just "5.0"
shanecowherd
left a comment
There was a problem hiding this comment.
Do we need to address any other types?
|
Thank you Shane! @tattn it's my colleague @shanecowherd commenting above. Shane, I won't need anything beyond Double that I can foresee right now. Float would probably be a good choice for the library more generally. @tattn probably knows what types are otherwise supported by the library. |
|
Thank you for your PR 👍 I created Could you please share the use case? |
|
Thank you for your feedback @tattn I'm happy to share our use case which may be surprising. I'll try to explain the use case simply:
Unfortunately in JSON, a Double like "1.00" can be written as "1" and so RN sends @tattn Would you be open to supporting this use case in your library if it's not a lot of extra work? If you do decide to support this use case, this PR would be needed for that. If you don't want to support this use case, then I can maintain a fork of your repo at my company's organization and keep the fix localized to that fork. That's ok too. Example: Here is the function definition, in Swift, of a RN NativeModule function. This is what's called by JS. |
|
@andrewash I haven't used React Native in a production environment, so I wasn't aware of the issue where Double is converted to Int when treated as JSON in data transmission. This seems like a problematic specification 😢 Using DictionaryDecoder as a JSON decoder is an interesting idea, but overly flexible decoding might delay the detection of implementation errors. Here's what I suggest:
For 1: let decoder = DictionaryDecoder()
decoder.decodingStrategy = .json
try decoder.decode(JSON.self, from: jsonDictionary)Setting For 2: struct RNDouble: Decodable, Equatable {
var value: Double
init(_ value: Double) {
self.value = value
}
init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
do {
value = try container.decode(Double.self)
} catch {
value = Double(try container.decode(Int.self))
}
}
}
struct Model: Decodable, Equatable {
let double: RNDouble
}This approach directly addresses the issue but might be slightly cumbersome due to type nesting. What are your thoughts on these proposals? |
Related Issue
#21
Description
Int literals cannot be cast as a Double using
as?soDouble(<Int>)must be used instead.JSON has only one Number type, and allows "5" to be considered a Double, not just "5.0"
However MoreCodable's DictionaryDecoder always decoded "3" as an Int so we would need a way to convert it to a Double to support JSON's flexible number formats.
Testing
I've included a new unit test that fails before this PR, and passes once the change is made to
func castOrThrow<T>()References
This railroad from json.org shows that
3is totally valid as a JSON number