【问题标题】:Instantiate Javascript classes that expect "new" keyword on KotlinJS在 Kotlin JS 中实例化需要“new”关键字的 Javascript 类
【发布时间】:2020-08-08 15:50:18
【问题描述】:

考虑到以下 javascript 代码(部分取自 Apollo Server 文档),它创建了一个 ApolloServer 实例并启动它。


const {ApolloServer} = require('apollo-server')

const server = new ApolloServer({ ... });

server.listen().then(({ url }) => {
  console.log(`Server ready at ${url}`);
});

现在考虑使用 KotlinJS 复制相同的行为。 首先,Kotlin 没有“new”关键字,按预期调用 ApolloServer() 将不起作用但会引发错误(TypeError: Class constructor ApolloServer cannot be invoked without 'new')。

// We can banally represent part of the code above like:
external fun require(module: String): dynamic
val ApolloServer = require("apollo-server").ApolloServer

// ApolloServer is a js class

声明一个外部类,如:

external open class ApolloServer() {
    open fun listen(vararg opts: Any): Promise<Any>
    operator fun invoke(): Any
}

并将其设置为 ApolloServer 类型没有帮助。

我们如何复制“new ApolloServer()”调用?

【问题讨论】:

  • 对不起,我不知道 Kotlin,但如果它有 JS 互操作,则必须有一种惯用的方式来调用 new。一种创可贴的解决方法是实施function createServer(...) { return new ApolloServer(...) }?
  • 我不知道 K/JS 但你可能需要在没有 new 关键字的情况下调用它,它会实例化一个新实例。因为 Kotlin 中没有 new 关键字(至少我们在 Kotlin/JVM 中所做的)
  • 谢谢:我可能会制作其他包含工厂的 js 文件,例如 createServer,然后导入它们。这与我最初认为的结论相同,但必须有办法避免这种做法。 AnimeshSahu:我也在 JVM 中使用 Kotlin,并开始将它与 node.js 一起使用。它非常强大,但缺少文档。很多时候我必须分析 javascript 输出以了解它是如何工作的,因为没有太多解释。
  • 我找到的唯一解决方案是以下一个,但它没有按预期工作:discuss.kotlinlang.org/t/… 我将尝试对此进行一些实验并分享解决方案。

标签: javascript kotlin kotlin-js kotlin-js-interop


【解决方案1】:

为了解决这个问题,我发现了一种基于 JsModule 注解的有趣方法。我们需要创建一个 Kotlin 文件来代表我们要导入的那个 javascript 模块,在我的例子中是“apollo-server”。

@file:JsModule("apollo-server")
@file:JsNonModule
package com.package

import kotlin.js.Promise

external interface ServerInfo {
    var address: String
    var family: String
    var url: String
    var subscriptionsUrl: String
    var port: dynamic /* Number | String */
        get() = definedExternally
        set(value) = definedExternally
    var subscriptionsPath: String
    var server: Any
}

external open class ApolloServer(config: Any? /* ApolloServerExpressConfig & `T$0` */) : Any {
    open var httpServer: Any
    open var cors: Any
    open var onHealthCheck: Any
    open var createServerInfo: Any
    open fun applyMiddleware()
    open fun listen(vararg opts: Any): Promise<ServerInfo>
    open fun stop(): Promise<Unit>
}

通过上面的代码,我们基本上描述了我们期望在 apollo-server 模块中找到的内容以及如何将其映射到 Kotlin 中。

在我们的 Kotlin 主函数中,我们不必指定任何 require(...),只需使用我们的 ApolloServer 类,例如:

    ApolloServer(null).listen().then {
       console.log(it)
    }

使用这种方法,Kotlin 会正确地转换它,使用 javascript 中的 new 关键字。

转译版本提取:

  function main$lambda(it) {
    console.log(it);
    return Unit;
  }
  function main() {
    (new ApolloServer(null)).listen().then(main$lambda);
  }

此代码只是一个示例,如果没有适当的配置,ApolloServer 将不会被初始化,例如,包含一个可为空的配置。

【讨论】:

  • 我想用库 JSZip 来实现它,但是当我调用它时,它会显示 is not a constructor。你碰巧知道怎么做吗?声明:external open class JSZip { open fun loadAsync(data: Blob, vararg options: Any) : Promise&lt;JSZip&gt; open fun file(name: String) : ZipObject }。用法:JSZip().loadAsync(file).then(onFulfilled = { zip -&gt; /*code here*/ }).
猜你喜欢
  • 1970-01-01
  • 2011-04-04
  • 1970-01-01
  • 2021-07-11
  • 1970-01-01
  • 2021-05-16
  • 2010-12-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多