Search code examples
iosswiftreactive-programmingcombine

optional execution path with combine


I'm new to Combine Swift for iOS and am struggling with an error about types.

I have a case to save users and optionally save roles if they are provided.

In either case, whether roles were provided or not I have to return the userId of the new record. Please guide me to fix the error.

I have used Just(userId) to take care of the case if roles are not provided, and it turns out to be the problem.

func save(_ user: User, roles: [Role]?) -> AnyPublisher<Int?, Error> {

    return repository.save(user)
            .flatMap { [weak self] userId -> AnyPublisher<Int?, Error> in

                if let roles = roles {
                    return repository.updateByUserId(userId, roles: roles)
                            .map { _ in userId } // return userId
                            .eraseToAnyPublisher()
                } else {
                    return Just(userId).eraseToAnyPublisher() // error - return userId
                }
            }
            .eraseToAnyPublisher()
}

Cannot convert return expression of type 'AnyPublisher<Int?, Never>' to return type 'AnyPublisher<Int?, any Error>'


Solution

  • The issue here is related to the error types. When using Just(userId), it returns a publisher with a completion of Never. However, your function is declared to return a Publisher with an error of type Error. To fix this, you need to introduce an error using the setFailureType operator on Just(userId).

    func save(_ user: User, roles: [Role]?) -> AnyPublisher<Int?, Error> {
        return repository.save(user)
            .flatMap { [weak self] userId -> AnyPublisher<Int?, Error> in
                if let roles = roles {
                    return repository.updateByUserId(userId, roles: roles)
                        .map { _ in userId }
                        .eraseToAnyPublisher()
                } else {
                    return Just(userId)
                        .setFailureType(to: Error.self) // Introduce an error type
                        .eraseToAnyPublisher()
                }
            }
            .eraseToAnyPublisher()
    }
    

    By using setFailureType(to: Error.self), you are effectively making Just(userId) conform to the expected error type, allowing it to fit into the AnyPublisher<Int?, Error> type.