Search code examples
kotlinkotlin-jskotlin-js-interop

Kotlin/JS external declaration - "Name contains illegal chars that can't appear in JavaScript identifier"


EDIT: This is not supported yet and tracked on Kotlin YouTrack


I'm trying to write a Kotlin external declaration matching the following Typescript interface (this is valid TS to represent JavaScript accesses via headers['content-length']):

export interface Headers {
  'content-length'?: string;
}

Dukat generates the following, which should be considered valid:

external interface Headers {
    var `content-length`: String? get() = definedExternally; set(value) = definedExternally
}

But now the compiler complains with:

Name contains illegal chars that can't appear in JavaScript identifier

It is true that it can't appear in a JS identifier, but it doesn't have to. All Kotlin accesses to this property like:

val length = headers.`content-length`

could be valid if compiled to const length = headers["content-length"].

I tried to use @JsName to work around it the following ways:

  • @JsName("content-length")
  • @JsName("'content-length'")
  • @JsName("\"content-length\"")

But all of these fail because they only allow strings that are valid JS identifiers. Is there a way to work around this?


Solution

  • I suggest working around this problem by defining an empty interface to stand in for such objects in Kotlin, plus an extension property to get and set the value:

    external interface KHeader // stands in for JavaScript objects with content-length property
    
    var KHeader.contentLength: String
       get() = this.asDynamic()["content-length"]
       set(value) { this.asDynamic()["content-length"] = value }
    

    In this way you can use Header JavaScript objects in Kotlin with camel case (see playground):

    fun main() {
        val jsObject = js("{}")
        jsObject["content-length"] = "44"
        val randomHeader = jsObject as KHeader
        println(randomHeader.contentLength) // prints 44
        randomHeader.contentLength = "55"
        println(randomHeader.contentLength)  // prints 55
    }