Kotlin / JS外部声明-“名称包含不能在JavaScript标识符中出现的非法字符”

时间:2019-06-03 21:15:29

标签: kotlin kotlin-js kotlin-js-interop

我正在尝试编写一个与以下打字稿接口匹配的外部声明(这是表示通过headers['content-length']进行JavaScript访问的有效TS):

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

Dukat生成以下内容,应将其视为有效:

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

但是现在编译器抱怨:

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

的确,它不能出现在JS标识符中,但不是必须的。所有Kotlin都可以访问此属性,例如:

val length = headers.`content-length`

如果编译为let length = headers["content-length"],可能是有效的。

我尝试使用@JsName通过以下方式解决该问题:

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

但是所有这些都失败了,因为它们将字符串限制为有效的标识符。 有办法解决这个问题吗?

编辑:我打开了一个issue on Kotlin YouTrack

3 个答案:

答案 0 :(得分:1)

问题在于连字符- Javascript 中不是有效的标识符。这意味着您不能声明这样的变量:

var content-length = 4

您只能执行以下操作:var contentLength = 4

Kotlin Kultiplatform不允许您编写无法编译为目标平台的通用代码,这就是即使这是有效的Kotlin代码的原因:

var `content-length`: String? // ...

由于 JavaScript 的限制,您仍然不能在多平台环境中使用它。

请注意,尽管这可能是有效的 Typescript 代码,但Kotlin没有Typescript目标,只有Javascript目标,因此请记住这一点。

答案 1 :(得分:1)

我建议通过在 Kotlin 中定义一个空接口来代表此类对象来解决这个问题,并加上一个扩展属性来获取和设置值:

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 }

通过这种方式,您可以在 Kotlin 中使用 Header JavaScript 对象与驼峰式大小写(参见 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
}

答案 2 :(得分:0)

在JSON中允许使用连字符,如果您使用刻度(``),我相信在JavaScript中可以使用连字符。在使用jsObject时,我遇到了相同的连字符问题,从字面上看,这就是解决方案。

我的连字符问题和此解决方案:

pluginsOpts = jsObject<dynamic> {
        this["grapesjs-tabs"] = jsObject<dynamic> {
            tabsBlock = jsObject<dynamic> {
                category = "Extra"
            }
        }
}

从字面上尝试:

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

我无法在外部使用此功能,但这是一个很好的连字符破解,可能会有所帮助。使用方法如下:与其定义一个外部对象,不如使用一个jsObject {}。您可以嵌套它们,但一定要在每层中明确包含动态标识符,尤其是如果必须在不同层中使用多个this来克服连字符问题时。这是您的解决方案

val Header = jsObject<dynamic> {
    this["content-length"] = "something"
}

让“这”成为您的课程。