The underlying problem here is that the type you want is Void, but Void is not Decodable, and you can't make it Decodable because non-nominal types (like Void) can't be extended. This is just a current limitation of Swift.
The right solution to this is overloading. Create two methods:
// For values
func request<D: Decodable>(from urlString: String,
useToken: Bool = false,
requestType: RequestType = .get,
body: Data? = nil,
expecting type: D.Type,
completion: @escaping (Result<D>) -> Void) {}
// For non-values
func request(from urlString: String,
useToken: Bool = false,
requestType: RequestType = .get,
body: Data? = nil,
completion: @escaping (Error?) -> Void) {}
Create another shared method that turns a request into Data and that both can call:
func requestData(from urlString: String,
useToken: Bool = false,
requestType: RequestType = .get,
body: Data? = nil,
completion: @escaping (Result<Data>) -> Void) {}
Your decoding request function will now convert .success(Data)
into a D
. Your non-decoding request function will throw away the data (or possibly ensure that it is empty if you're pedantic about it), and call the completion handler.
If you wanted your code to be a little more parallel, so that it always passes a Result rather than an Error?, then you can still have that with a tweak to the signature:
func request(from urlString: String,
useToken: Bool = false,
requestType: RequestType = .get,
body: Data? = nil,
completion: @escaping (Result<Void>) -> Void) {}
But overloading is still the answer here.
(OLD ANSWERS)
There's no problem with passing nil
here, as long as D
can somehow be inferred. But there has to be a way to infer D
. For example, the following should be fine:
request(from: "") { (result: Result<Bool?>) in
print(result)
}
What would not be fine would be this:
request(from: "") { (result) in
print(result)
}
Because in that case, there's no way to determine what D
is.
That said, given your goal, you don't want Type
to be optional anyway. As you say, sometimes the result is "returns nothing." The correct type for "returns nothing" is Void
, not nil.
func request<D: Decodable>(from urlString: String,
useToken: Bool = false,
body: Data? = nil,
expecting type: D.Type = Void.self, // <<----
completion: @escaping (Result<D>) -> Void)
(I'm assuming you then want Result<D>
rather than Result<D?>
, but either could be correct depending on your precise use case.)
Void
is a normal type in Swift. It is a type with exactly one value: ()
, the empty tuple.