I've created a Kotlin Multiplatform application that generates a JS and TypeScript output file, i'm trying to make use of those output files inside a TypeScript project I'm fairly new to TypeScript as well as the whole npm ecosystem
The first package.json inside the hotel directory looks like this:
{
"main": "kotlin/hotel.js",
"devDependencies": {
"webpack": "4.42.1",
"webpack-cli": "3.3.11",
"source-map-loader": "0.2.4",
"webpack-dev-server": "3.10.3",
"css-loader": "3.4.2",
"style-loader": "1.1.3"
},
"dependencies": {
"kotlin": "file:/home/vlad/Code/hotel-state/build/js/packages_imported/kotlin/1.4.0-M2",
"kotlin-source-map-loader": "file:/home/vlad/Code/hotel-state/build/js/packages_imported/kotlin-source-map-loader/1.4.0-M2"
},
"peerDependencies": {},
"optionalDependencies": {},
"bundledDependencies": [],
"name": "hotel",
"version": "1.0.0"
}
The second package.json inside the js directory looks like this:
{
"private": true,
"workspaces": [
"packages/hotel",
"packages/hotel-test"
],
"devDependencies": {},
"dependencies": {},
"peerDependencies": {},
"optionalDependencies": {},
"bundledDependencies": [],
"name": "hotel",
"version": "1.0.0"
}
From the hotel directory, i've done
sudo npm link hotel
In my second project, i now add this to the package.json
followed by an npm install
"dependencies": {
"hotel": "file:/usr/lib/node_modules/hotel",
"lit-html": "^1.2.1"
},
When i hit autocomplete, i can see the hotel package, but it keeps on showing a red line underneath it. When i try to use it in my other TypeScript files, it stops compiling
The typescript headers in that hotel.d.ts has a namespace
declare namespace hotel {
type Nullable<T> = T | null | undefined
namespace com.harakati.hotel {
/* ErrorDeclaration: Class com.harakati.hotel.TH with kind: OBJECT */
}
namespace com.harakati.hotel {
class Room {
constructor(roomNumber: Nullable<number>)
static Room_init_$Create$(roomNumber: Nullable<number>, $mask0: number, $marker: Nullable<any /*Class kotlin.js.DefaultConstructorMarker with kind: OBJECT*/>): com.harakati.hotel.Room
roomNumber: number;
}
}
Am i doing the linking correctly?
Am i including this linked package correctly?
Is there anythin else that i might be missing?
Turns out the generated TypeScript headers in Kotlin 1.4 M2 aren't being exported and somebody has already logged a bug for it
https://youtrack.jetbrains.com/issue/KT-37883
A quick and dirty workaround i wrote is to run some Kotlin script at the end of a Gradle build to post-process the generated TypeScript.
Include this inside the Kotlin block in your build.gradle.kts
and the generated TS headers will import without problems in the TS project.
gradle.buildFinished {
println("==============================================================")
val path = "$buildDir/js/packages/${project.name}/kotlin/${project.name}.d.ts"
println("Making some adjustments to \n$path")
val newLines = mutableListOf<String>()
println("==============================================================")
if (File(path).exists()) {
File(path).readLines().forEach { line ->
if (line.startsWith("declare namespace") || line.startsWith("}")) {
"// $line".let {
newLines.add(it)
println(it)
}
} else if (line.trim().startsWith("namespace")) {
line.replace("namespace", "export namespace").let {
newLines.add(it)
println(it)
}
} else {
line.let {
newLines.add(it)
println(it)
}
}
}
File(path).writeText(newLines.joinToString("\n"))
} else {
println("$path does not exist")
}
println("==============================================================")
}
Inside package.json
in your TypeScript project, include it becomes straight forward
"dependencies": {
"hotel": "/home/vlad/Code/.../hotel/build/js",
"lit-html": "^1.2.1",
"tslib": "^2.0.0"
},
or simply use npm link
to create a simlink to the generated output which then allows you to point to point to the link instead of the absolute path which could change if you move stuff around.