considering the following javascript code (partially taken from Apollo Server documentation), it creates an instance of ApolloServer and start it.
const {ApolloServer} = require('apollo-server')
const server = new ApolloServer({ ... });
server.listen().then(({ url }) => {
console.log(`Server ready at ${url}`);
});
Now consider to replicate the same behaviour using KotlinJS.
Firstly, Kotlin doesn't have the "new" keyword and calling ApolloServer() as expected, won't work but raise an error (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
Declaring an external class like:
external open class ApolloServer() {
open fun listen(vararg opts: Any): Promise<Any>
operator fun invoke(): Any
}
and set it as ApolloServer type doesn't help.
How do we replicate "new ApolloServer()" call?
To solve this problem I found an interesting approach based on JsModule annotation. We need to create a Kotlin file that represent that javascript module we want to import, in my case "apollo-server".
With the above code we are basically describing what we expect to find in the apollo-server module and how to map it into Kotlin.
In our Kotlin main function we don't have to specify any require(...) but just use our ApolloServer class like:
Using this approach Kotlin would transpile it correctly, using the new keyword in javascript.
Transpiled version extract:
This code is just an example, ApolloServer won't be initialized without a proper configuration, this case, for example, contains a nullable configuration.