Compile a JS library with types defined in NPM dependency

I’m trying to write a library using the new Kotlin/JS IR compiler. Specifically, I want to write the library using Kotlin, but to publish it as a NPM package to be used in a Typescript/Node project.

I have a NPM dependency in the project defined which already has TS types defined and a readily available.

To allow the library to work smoothly together with using it in tandem with this dependency in a project it would make sense to use the already defined TS types when available.

As an example, I want to define a function in my library foo(message: Message) where Message is actually a type coming from the NPM dependency.

What I hoped to be able to achieve would be an output where the generated types in my compiled output contained something like this:

import * as someDep from 'some-dependency'

export namespace foo.bar.baz {
    function foo(message: someDep.Message): void;
}

However, I haven’t been able to get this done. Instead, the Message is simply just there as an undefined type, meaning the d.ts file is essentially broken.

For an example of a simple project which tries to do what I’m asking about see: GitHub - jsfr/sample-kotlin-js

Here I create a simple abstract class named Consumer which should be able to take a Message type from the external google-protobuf NPM library. However, in the resulting d.ts file the Message is present with no definition of itself.

Is what I’m trying to do here possible or is there some other approach I should take instead? This seems like an important thing to be able to do for good interoperability.

What you would be able to do is to use Dukat to generate a Kotlin import from the typescript (you may still want to adjust it somewhat - TS/JS are quite different from Kotlin in their handling of parameter and return types).

Definitely Dukat can help in going from TS to Kotlin.

That however doesn’t really solve the situation I’m describing. If I were to generate types for the entire dependency using Dukat I still end up in a situation where the typings in the compiled JS/TS bundle would not be using imported types from the dependency, but would instead be using new types defined in my library but for a NPM dependency.

This would make the library quite a bit harder to work with in a JS/TS context if say e.g. the output of my library is to be used by another library having the same third-party dependency.

First of all, the only way that type definitions can be/are used in Kotlin is by transforming them into kotlin definitions. This is what Dukat does, and what you can get automatically with the build system in cases. These definitions describe existing types/functions, but don’t define new ones. As such the only compatibility issue would be if you were to use conflicting defintions in the same Kotlin project. The solution to that is to not export the definitions as part of your project. The definitions are certainly not going to create a problem for JavaScript/TypeScript libraries as they would ignore Kotlin definitions.

Of course if you want to provide typescript definitions for your library you need to check how that works, but then it would be a typescript dependency conflict, not a Kotlin one.

My original question is not about how I can use type information in Kotlin for a NPM dependency. I understand how to do this either by hand-writing the Kotlin types or by generating them using Dukat.

My question is about the situation where I want to write a library which is to be used in a Typescript project. That means my question is indeed about the Typescript definitions that will be provided when I compile my library from Kotlin to JS/TS.

In bullet points the problem I’m facing is:

  • Write a library in Kotlin for a Typescript project
  • Use an NPM dependency in the Kotlin project (this requires defining the types of the dependency using e.g. Dukat)
  • Compile the library such that the provided type definitions utilizes the 3rd party Typescript definitions in the compiled output (Currently the type definitions would all be based on the ones I define in the Kotlin project instead which can result in bad interoperability between my new library and any other library which both use this 3rd party NPM dependency and e.g. pass objects from it to each other).

I had a dig around. Looking at https://youtrack.jetbrains.com/issue/KT-16604 it is supported to generate typescript declarations from Kotlin. As documented, this is only done for @JsExport symbols, and there is a specific comment here about currently not generating any typescript declarations for dependencies. As such you shouldn’t have “conflicts”.

Note also, that at runtime both kotlin and typescript revert back to untyped javascript. The type information is lost. Also, the definitions in Kotlin do not create types or add code, so the original library is called for that (the only place where I see potential problems is for types that don’t provide a proper prototype and as such require the user to put in the right fields).