withCheckedThrowingContinuation and typed Errors

Hello Folks

I am experimenting with the new typed errors, and kinda hit a challenge, and that is in particular with withCheckedThrowingContinuation. It uses any Error which is opposite to the specific error I want to use, here is a sample code:

enum OperationFailed: Error {
  case oops
}

@MainActor final class Model {

  var operationContinuation: CheckedContinuation<Void,OperationFailed>?

  func doOperation() async throws(OperationFailed) {
    try await withCheckedThrowingContinuation { continuation in
      // error: Cannot assign value of type 'CheckedContinuation<Void, any Error>' to type 'CheckedContinuation<Void, OperationFailed>'
      operationContinuation = continuation
    }
  }

  func completeOperation() {
    operationContinuation?.resume()
    operationContinuation = nil
  }

  func failOperation() {
    operationContinuation?.resume(throwing: .oops)
    operationContinuation = nil
  }
}

I tried casting but that also produced an error. Is there some pattern I must follow when i want to use typed throws in conjunction with continuation or are we stuck with loosing the error type in these situations?

Thanks in advance

1 Like

First, read Where is FullTypedThrows? - #15 by hborla.


You can't actually create a Continuation of any kind, with anything but Never or any Error. This has not changed with Xcode 16 Beta 1. However, you can at least mask this outside of the Model type, either with an overload, a do-catch statement, or a function that can apply that statement.

func doOperation() async throws(OperationFailed) {
  try await forceError(OperationFailed.self) {
    try await withCheckedThrowingContinuation { continuation in
      operationContinuation = continuation
    }
  }
}
func forceError<Success, Error: Swift.Error>(
  _: Error.Type,
  _ body: () async throws -> Success
) async throws(Error) -> Success {
  do {
    return try await body()
  } catch {
    throw error as! Error
  }
}
1 Like

What you can do for now is using CheckedContinuation<Result<T,Failure>,Never> and rethrow the typed Failure using the result.

enum OperationFailed: Error {
  case oops
}

@MainActor final class Model {

  var operationContinuation: CheckedContinuation<Result<Void,OperationFailed>, Never>?

  func doOperation() async throws(OperationFailed) {
      try await withCheckedContinuation { continuation in
      operationContinuation = continuation
    }.get()
  }

  func completeOperation() {
    operationContinuation?.resume(success: ())
    operationContinuation = nil
  }

  func failOperation() {
    operationContinuation?.resume(failure: .oops)
    operationContinuation = nil
  }
}

extension CheckedContinuation where E == Never {
    
    func resume<Value, Failure:Error>(failure: Failure) where T == Result<Value,Failure> {
        resume(returning: .failure(failure))
    }
    
    func resume<Value, Failure:Error>(success: Value) where T == Result<Value,Failure> {
        resume(returning: .success(success))
    }
    
}
2 Likes

Thank you both for the suggestions, I saw typed throws was there when trying code but wasn't aware that the full feature was not included. I will use these workarounds in the meantime.