在 Kotlin JS 中实例化期望 "new" 关键字的 Javascript 类
Instantiate Javascript classes that expect "new" keyword on KotlinJS
考虑到以下 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
声明外部 class 如:
external open class ApolloServer() {
open fun listen(vararg opts: Any): Promise<Any>
operator fun invoke(): Any
}
并将其设置为 ApolloServer 类型没有帮助。
我们如何复制 "new ApolloServer()" 调用?
为了解决这个问题,我发现了一种基于 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[=10=]` */) : 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 main 函数中,我们不必指定任何 require(...),只需使用我们的 ApolloServer class,例如:
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 将不会被初始化,例如,本例包含一个可为空的配置。
考虑到以下 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
声明外部 class 如:
external open class ApolloServer() {
open fun listen(vararg opts: Any): Promise<Any>
operator fun invoke(): Any
}
并将其设置为 ApolloServer 类型没有帮助。
我们如何复制 "new ApolloServer()" 调用?
为了解决这个问题,我发现了一种基于 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[=10=]` */) : 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 main 函数中,我们不必指定任何 require(...),只需使用我们的 ApolloServer class,例如:
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 将不会被初始化,例如,本例包含一个可为空的配置。