Skip to content
Experimental

JS 普通对象编译器插件

JavaScript (JS) 普通对象编译器插件(js-plain-objects)允许你以类型安全的方式创建和复制普通的 JS 对象。

在这里你可以找到关于 JS 普通对象的信息,以及如何在你的 Kotlin/JS 项目中使用 js-plain-objects 编译器插件。

js-plain-objects 插件仅适用于新的 K2 Kotlin 编译器。

JS 普通对象

普通对象是经由对象字面量({})创建的简单 JS 对象,包含数据属性。许多 JS API 接受/返回普通 JS 对象用于配置或数据交换。

通过 js-plain-objects 插件,你可以声明一个 Kotlin 外部接口来描述对象结构,并使用 @JsPlainObject 进行注解。编译器会生成便捷函数来构建和复制此类对象,同时保留 Kotlin 的类型安全。

启用插件

js-plain-objects 插件添加到你的项目 Gradle 配置文件中,如以下 Kotlin DSL 所示:

kotlin
// build.gradle.kts
plugins {
    kotlin("multiplatform") version "2.2.20"
    kotlin("plugin.js-plain-objects") version "2.2.20"
}

kotlin {
    js {
        browser() // or nodejs()
    }
}
groovy
// build.gradle
plugins {
    id 'org.jetbrains.kotlin.multiplatform' version '2.2.20'
    id 'org.jetbrains.kotlin.plugin.js-plain-objects' version '2.2.20'
}

kotlin {
    js {
        browser() // or nodejs()
    }
}

声明普通对象类型

启用 js-plain-objects 插件后,你就可以声明一个普通对象类型。使用 @JsPlainObject 注解一个外部接口。例如:

kotlin
@JsPlainObject
external interface User {
    val name: String
    val age: Int
    // You can use nullable types to declare a property as optional
    val email: String? 
}

当插件处理这样的接口时,它会生成一个伴生对象,其中包含两个用于创建和复制对象的辅助函数:

kotlin
@JsPlainObject
external interface User {
    val name: String
    val age: Int
    val email: String?

    // Generated by the plugin
    @JsExport.Ignore
    companion object {
        inline operator fun invoke(name: String, age: Int, email: String? = NOTHING): User =
            js("({ name: name, age: age, email: email })")

        inline fun copy(source: User, name: String = NOTHING, age: Int = NOTHING, email: String? = NOTHING): User =
            js("Object.assign({}, source, { name: name, age: age, email: email })")
    }
}

根据上述示例:

  • nameage 声明时没有可空性标记,因此它们是必需的。
  • email 声明为可空类型,因此它是可选的,可以在创建时跳过。
  • 操作符 invoke 用提供的属性构建一个新的 JS 普通对象。
  • copy 函数通过浅拷贝 source 并覆盖任何指定的属性来创建新对象。
  • 伴生对象被标记为 @JsExport.Ignore,以避免这些辅助函数泄露到 JS 导出中。

使用普通对象

使用生成的辅助函数创建和复制对象:

kotlin
fun main() {
    val user = User(name = "Name", age = 10)
    val copy = User.copy(user, age = 11, email = "[email protected]")

    println(JSON.stringify(user))
    // { "name": "Name", "age": 10 }
    println(JSON.stringify(copy))
    // { "name": "Name", "age": 11, "email": "[email protected]" }
}

Kotlin 代码会编译为 JavaScript:

javascript
function main () {
    var user = { name: "Name", age: 10 };
    var copy = Object.assign({}, user, { age: 11, email: "[email protected]" });

    println(JSON.stringify(user));
    // { "name": "Name", "age": 10 }
    println(JSON.stringify(copy));
    // { "name": "Name", "age": 11, "email": "[email protected]" }
}

任何通过这种方式创建的 JavaScript 对象都是安全的。当你使用错误的属性名或值类型时,会遇到编译期错误。这种方式也是零成本的,因为生成的代码会被内联为简单的对象字面量和 Object.assign 调用。

接下来

关于与 JavaScript 的互操作性,请参阅 从 Kotlin 使用 JavaScript 代码动态类型 文档以了解更多信息。