firebasekotlinkotlin-coroutines

Type mismatch: inferred type is Resource<Exception> but Resource<T> was expected


For my firebase job I created base firebase repository to handle onSuccess and on error.

I can use it for all my firebase job but when I try to handle error I got this error.

why can I post documentReference but can't post exception.

Here is my code:

suspend inline fun <T> firebaseJob(crossinline task: () -> Task<T>): Resource<T> {
    return withContext(Dispatchers.IO) {
        try {
            suspendCancellableCoroutine<Resource<T>> { continuation ->
                task().addOnSuccessListener { documentReference ->
                    continuation.resume(Resource.success(documentReference))
                }.addOnFailureListener { exception ->
                    continuation.resume(Resource.error(exception))
                }
            }
        } catch (e: Exception) {
            e.printStackTrace()
            Resource.error(null)
        }
    }
}

Here is my Resource class

data class Resource<out T>(val status: Status, val data: T?) {

    companion object {
        fun <T> success(data: T?): Resource<T> {
            return Resource(Status.SUCCESS, data)
        }

        fun <T> error(data: T?): Resource<T> {
            return Resource(Status.ERROR, data)
        }

        fun <T> loading(data: T?): Resource<T> {
            return Resource(Status.LOADING, data)
        }
    }
}

enum class Status {
    SUCCESS,
    ERROR,
    LOADING
}```

Type mismatch


Solution

  • Your firebaseJob returns a Resource<T> where T is whatever type you use when you call this function. On the line where you have the error, you need to pass a Resource<T> to the resume function but you are passing a Resource<Exception> instead.

    When you call Resource.error(exception) it creates a Resource<Exception> because of the way you've defined your Resource class. Your Resource class needs to have an error function which still returns a Resource<T>, the same way that the Kotlin stdlib Result function does. For that to happen, you need to make data to be of type Any? and then cast it to T when you return it. See the Result implementation to see how it's done.

    An alternative way is to make Resource<T> a sealed class or interface, and create implementation classes SuccessResource<T>, LoadingResource<T> and ErrorResource<T>. The ErrorResource<T> class would then take an Exception object but would still be a subclass of Resource<T>.

    Your firebaseJob code will compile ok if you replace Resource as follows:

    sealed interface Resource<out T> {
        val status: Status
        val data: T? get() = null
        val exception: Exception? get() = null
    
    
        private class LoadingResource<T>(override val data: T?) : Resource<T> {
            override val status get() = Status.LOADING
        }
    
        private class SuccessResource<T>(override val data: T?) : Resource<T> {
            override val status get() = Status.SUCCESS
        }
    
        private class ErrorResource<T>(override val exception: Exception?) : Resource<T> {
            override val status get() = Status.ERROR
        }
    
        companion object {
            fun <T> success(data: T?): Resource<T> = SuccessResource(data)
    
            fun <T> error(exception: Exception?): Resource<T> = ErrorResource(exception)
    
            fun <T> loading(data: T?): Resource<T> = LoadingResource(data)
        }
    }