Issue #860

JSONEncoder deals with type-safe, so we need to declare an enum JSONValue for all possible types. We also need a custom initializer to init JSONValue from a JSON Dictionary

import Foundation

enum JSONValue {
    case string(String)
    case int(Int)
    case double(Double)
    case bool(Bool)
    case object([String: JSONValue])
    case array([JSONValue])
}

extension JSONValue: Encodable {
    public func encode(to encoder: Encoder) throws {
        var container = encoder.singleValueContainer()
        switch self {
        case .string(let string): try container.encode(string)
        case .int(let int): try container.encode(int)
        case .double(let double): try container.encode(double)
        case .bool(let bool): try container.encode(bool)
        case .object(let object): try container.encode(object)
        case .array(let array): try container.encode(array)
        }
    }
}

extension JSONValue {
    init?(any: Any) {
        if let value = any as? String {
            self = .string(value)
        } else if let value = any as? Int {
            self = .int(value)
        } else if let value = any as? Double {
            self = .double(value)
        } else if let value = any as? Bool {
            self = .bool(value)
        } else if let json = any as? [String: Any] {
            var dict: [String: JSONValue] = [:]
            for (key, value) in json {
                dict[key] = JSONValue(any: value)
            }
            self = .object(dict)
        } else if let jsonArray = any as? [Any] {
            let array = jsonArray.compactMap { JSONValue(any: $0) }
            self = .array(array)
        } else {
            return nil
        }
    }
}

var dict: [String: Any] = [
    "anArray": [1, 2, 3],
    "anObject": [
        "key1": "value1",
        "key2": "value2"
    ],
    "aString": "hello world",
    "aDouble": 1.2,
    "aBool": true,
    "anInt": 12
]


let encoder = JSONEncoder()
let value = JSONValue(any: dict)
let data = try! encoder.encode(value)
print(String(data: data, encoding: .utf8))