在默认的 Promise 构造函数中使用 Kotlin JS 中返回动态的 JS 函数会导致 ClassCastException

Using JS function returning dynamic in Kotlin JS within the default Promise constructor results in ClassCastException

我在尝试将 gapi 调用转换为 Promises 时遇到此错误,但我想调用其他函数可能会导致相同的问题。首先,我在页面中将库作为脚本添加:

script(src = "https://apis.google.com/js/platform.js") {
    async = true
    defer = true
}

接下来,我从 window 中获取了 gapi 对象:

import kotlinx.browser.window
import org.w3c.dom.get

val gapi = window["gapi"]

最后,我像这样使用 load 函数:

import kotlin.js.Promise

fun loadGapi() = Promise<Unit> { resolve, _ ->
    gapi.load("client:auth2") { resolve(Unit) }
}

在 IDE 中给我一个警告:

这导致在页面内调用时出现以下错误:

Uncaught (in promise) ClassCastException {message: undefined, cause: undefined, name: 'ClassCastException', stack: 'ClassCastException\n at THROW_CCE (http://localh… (http://localhost:3000/static/app.js:4930:14)'}

不确定为什么会这样。我尝试用已评估的 JS 代码重现该问题,但无济于事:

import kotlin.js.Promise

fun loadGapi(): Promise<Any> {
    val functionReturningUndefined =
        js("function (resolve) { resolve('test'); return undefined; }")
    return Promise { resolve, _ ->
        functionReturningUndefined { param -> resolve(param as Any) } as Unit
    }
}

无论如何,忽略函数的 return 值并添加 return@Promise Unit 即可解决问题,如下所示:

fun loadGapi() = Promise<Unit> { resolve, _ ->
    gapi.load("client:auth2") { resolve(Unit) }
    return@Promise Unit
}

或者,可以添加专门针对 dynamic return 类型的扩展函数(我把我的放在 shared/Promises.kt 中):

fun <T> Promise(executor: (resolve: (T) -> Unit, reject: (Throwable) -> Unit) -> dynamic) =
    Promise<T> { resolve, reject ->
        executor(resolve, reject)
        Unit
    }

然后简单地:

import shared.Promise

fun loadGapi() = Promise<Unit> { resolve, _ ->
    gapi.load("client:auth2") { resolve(Unit) }
}