Взаимодействие с JavaScript
Kotlin/Wasm позволяет использовать код JavaScript в Kotlin, а код Kotlin — в JavaScript.
Как и в Kotlin/JS, компилятор Kotlin/Wasm поддерживает взаимодействие с JavaScript. Если вы знакомы с взаимодействием в Kotlin/JS, то заметите, что взаимодействие в Kotlin/Wasm устроено похожим образом. Однако есть ключевые отличия, которые следует учитывать.
Использование кода JavaScript в Kotlin
Узнайте, как использовать код JavaScript в Kotlin с помощью объявлений external, функций с фрагментами кода JavaScript и аннотации @JsModule.
Внешние объявления
Внешний код JavaScript по умолчанию недоступен в Kotlin. Чтобы использовать код JavaScript в Kotlin, можно описать его API с помощью объявлений external.
Функции JavaScript
Рассмотрим эту функцию JavaScript:
function greet (name) {
console.log("Hello, " + name + "!");
}
Её можно объявить в Kotlin как функцию external:
external fun greet(name: String)
У внешних функций нет тела, и их можно вызывать как обычные функции Kotlin:
fun main() {
greet("Alice")
}
Свойства JavaScript
Рассмотрим эту глобальную переменную JavaScript:
let globalCounter = 0;
Её можно объявить в Kotlin как внешнее свойство var или val:
external var globalCounter: Int
Эти свойства инициализируются извне. В коде Kotlin для свойств нельзя задавать инициализаторы = value.
Классы JavaScript
Рассмотрим этот класс JavaScript:
class Rectangle {
constructor (height, width) {
this.height = height;
this.width = width;
}
area () {
return this.height * this.width;
}
}
Его можно использовать в Kotlin как внешний класс:
external class Rectangle(height: Double, width: Double) : JsAny {
val height: Double
val width: Double
fun area(): Double
}
Все объявления внутри класса external неявно считаются внешними.
Внешние интерфейсы
В Kotlin можно описать структуру объекта JavaScript. Рассмотрим эту функцию JavaScript и возвращаемое ею значение:
function createUser (name, age) {
return { name: name, age: age };
}
Посмотрите, как описать его структуру в Kotlin с помощью типа external interface User:
external interface User : JsAny {
val name: String
val age: Int
}
external fun createUser(name: String, age: Int): User
Внешние интерфейсы не содержат информации о типах во время выполнения и существуют только на этапе компиляции. Поэтому по сравнению с обычными интерфейсами внешние интерфейсы имеют ряд ограничений:
Их нельзя использовать в правой части проверок
is.Их нельзя использовать в выражениях с литералами классов (например,
User::class).Их нельзя передавать в качестве реифицированных аргументов типа.
Приведение типов с помощью
asк внешним интерфейсам всегда успешно.
Внешние объекты
Рассмотрим эти переменные JavaScript, содержащие объект:
let Counter = {
value: 0,
step: 1,
increment () {
this.value += this.step;
}
};
Их можно использовать в Kotlin как внешний объект:
external object Counter : JsAny {
fun increment()
val value: Int
var step: Int
}
Иерархия внешних типов
Как и обычные классы и интерфейсы, внешние объявления могут расширять другие внешние классы и реализовывать внешние интерфейсы. Однако нельзя смешивать внешние и невнешние объявления в одной иерархии типов.
Вызываемые объекты JavaScript с помощью @nativeInvoke
К функции-члену Kotlin объявления external (класса или интерфейса) можно применить аннотацию @nativeInvoke, чтобы её можно было вызывать как функцию JavaScript.
С этой аннотацией каждый вызов такой функции в Kotlin преобразуется в прямой вызов объекта JavaScript:
import kotlin.js.nativeInvoke
@OptIn(ExperimentalWasmJsInterop::class)
external class JsAction {
@nativeInvoke
operator fun invoke(data: String)
}
fun main() {
val action = JsAction()
action("Run task")
}
Функции Kotlin с кодом JavaScript
В код Kotlin/Wasm можно добавить фрагмент JavaScript, определив функцию с телом = js("code"):
fun getCurrentURL(): String =
js("window.location.href")
Если нужно выполнить блок инструкций JavaScript, заключите код в строке в фигурные скобки {}:
fun setLocalSettings(value: String): Unit = js(
"""{
localStorage.setItem('settings', value);
}"""
)
Если нужно вернуть объект, заключите фигурные скобки {} в круглые скобки ():
fun createJsUser(name: String, age: Int): JsAny =
js("({ name: name, age: age })")
Вызовы функции js() обрабатываются в Kotlin/Wasm особым образом и имеют ряд ограничений:
Вызову функции
js()необходимо передать строковый литерал в качестве аргумента.Вызов функции
js()должен быть единственным выражением в теле функции.Функцию
js()можно вызывать только из функций уровня пакета.Возвращаемый тип функции необходимо указывать явно.
Типы ограничены так же, как и для
external fun.
Компилятор Kotlin помещает строку с кодом в функцию в сгенерированном файле JavaScript и импортирует её в формате WebAssembly. Компилятор Kotlin не проверяет эти фрагменты JavaScript. Если в них есть синтаксические ошибки JavaScript, они будут обнаружены при запуске кода JavaScript.
Модули JavaScript
По умолчанию внешние объявления соответствуют глобальной области видимости JavaScript. Если снабдить файл Kotlin аннотацией @JsModule, все внешние объявления в нем будут импортированы из указанного модуля.
Рассмотрим этот пример кода JavaScript:
// users.mjs
export let maxUsers = 10;
export class User {
constructor (username) {
this.username = username;
}
}
Используйте этот код JavaScript в Kotlin с аннотацией @JsModule:
// Kotlin
@file:JsModule("./users.mjs")
external val maxUsers: Int
external class User : JsAny {
constructor(username: String)
val username: String
}
Взаимодействие с массивами
Массивы JavaScript JsArray<T> можно копировать в собственные типы Kotlin Array или List; аналогично, эти типы Kotlin можно копировать в JsArray<T>.
Чтобы преобразовать JsArray<T> в Array<T> или наоборот, используйте одну из доступных функций-адаптеров.
Вот пример преобразования между обобщенными типами:
val list: List<JsString> =
listOf("Kotlin", "Wasm").map { it.toJsString() }
// Uses .toJsArray() to convert List or Array to JsArray
val jsArray: JsArray<JsString> = list.toJsArray()
// Uses .toArray() and .toList() to convert it back to Kotlin types
val kotlinArray: Array<JsString> = jsArray.toArray()
val kotlinList: List<JsString> = jsArray.toList()
Для преобразования типизированных массивов в соответствующие типы Kotlin также доступны аналогичные функции-адаптеры (например, IntArray и Int32Array). Подробную информацию и реализацию см. в репозитории kotlinx-browser.
Вот пример преобразования между типизированными массивами:
import org.khronos.webgl.*
// ...
val intArray: IntArray = intArrayOf(1, 2, 3)
// Uses .toInt32Array() to convert Kotlin IntArray to JavaScript Int32Array
val jsInt32Array: Int32Array = intArray.toInt32Array()
// Uses toIntArray() to convert JavaScript Int32Array back to Kotlin IntArray
val kotlinIntArray: IntArray = jsInt32Array.toIntArray()
Использование кода Kotlin в JavaScript
Узнайте, как использовать код Kotlin в JavaScript с помощью аннотации @JsExport.
Функции с аннотацией @JsExport
Чтобы сделать функцию Kotlin/Wasm доступной для кода JavaScript, используйте аннотацию @JsExport:
// Kotlin/Wasm @JsExport fun addOne(x: Int): Int = x + 1
Функции Kotlin/Wasm, помеченные аннотацией @JsExport, доступны как свойства экспорта default сгенерированного модуля .mjs. После этого эту функцию можно использовать в JavaScript:
// JavaScript import exports from "./module.mjs" exports.addOne(10)
Компилятор Kotlin/Wasm умеет генерировать определения TypeScript для любых объявлений @JsExport в коде Kotlin. Эти определения можно использовать в IDE и инструментах JavaScript для автодополнения кода и проверки типов, а также для упрощения использования кода Kotlin из JavaScript и TypeScript.
Компилятор Kotlin/Wasm собирает все функции верхнего уровня, помеченные аннотацией @JsExport, и автоматически генерирует определения TypeScript в файле .d.ts.
Чтобы сгенерировать определения TypeScript, добавьте функцию generateTypeScriptDefinitions() в файл build.gradle.kts, в блок wasmJs{}:
kotlin {
wasmJs {
binaries.executable()
browser {
}
generateTypeScriptDefinitions()
}
}
Соответствие типов
В сигнатурах объявлений взаимодействия с JavaScript в Kotlin/Wasm разрешены только определенные типы. Эти ограничения одинаково применяются к объявлениям с external, = js("code") или @JsExport.
Посмотрите, как типы Kotlin соответствуют типам JavaScript:
Kotlin |
JavaScript |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
Тип функции, например |
Функция |
|
Любое значение JavaScript |
|
Непрозрачная ссылка на объект Kotlin |
Другие типы |
Не поддерживаются |
Также можно использовать nullable-версии этих типов.
Тип JsAny
Значения JavaScript представлены в Kotlin типом JsAny и его подтипами.
Стандартная библиотека Kotlin/Wasm предоставляет представления для некоторых из этих типов:
-
Пакет
kotlin.js:JsAnyJsBoolean,JsNumber,JsStringJsArrayPromise
Можно также создавать собственные подтипы JsAny, объявляя интерфейс или класс external.
Тип JsReference
Значения Kotlin можно передавать в JavaScript как непрозрачные ссылки с помощью типа JsReference.
Например, если нужно предоставить этот класс Kotlin User в JavaScript:
class User(var name: String)
Можно использовать функцию toJsReference(), чтобы создать JsReference<User> и вернуть его в JavaScript:
@JsExport
fun createUser(name: String): JsReference<User> {
return User(name).toJsReference()
}
Эти ссылки напрямую недоступны в JavaScript и ведут себя как пустые замороженные объекты JavaScript. Чтобы работать с этими объектами, нужно экспортировать в JavaScript дополнительные функции с помощью метода get(), в котором раскрывается значение ссылки:
@JsExport
fun setUserName(user: JsReference<User>, name: String) {
user.get().name = name
}
Можно создать класс и изменить его имя из JavaScript:
import UserLib from "./userlib.mjs"
let user = UserLib.createUser("Bob");
UserLib.setUserName(user, "Alice");
Параметры типа
Объявления взаимодействия с JavaScript могут иметь параметры типа, если их верхняя граница — JsAny или его подтипы. Например:
external fun <T : JsAny> processData(data: JsArray<T>): T
Обработка исключений
Для перехвата исключений JavaScript в коде Kotlin/Wasm можно использовать выражения Kotlin try-catch. Обработка исключений работает следующим образом:
Исключения, выброшенные в JavaScript: подробная информация доступна на стороне Kotlin. Если такое исключение распространяется обратно в JavaScript, оно больше не оборачивается в WebAssembly.
Исключения, выброшенные в Kotlin: их можно перехватить на стороне JavaScript как обычные ошибки JS.
Вот пример перехвата исключения JavaScript на стороне Kotlin:
external object JSON {
fun <T: JsAny> parse(json: String): T
}
fun main() {
try {
JSON.parse("an invalid JSON")
} catch (e: JsException) {
println("Thrown value is: ${e.thrownValue}")
// SyntaxError: Unexpected token 'a', "an invalid JSON" is not valid JSON
println("Message: ${e.message}")
// Message: Unexpected token 'a', "an invalid JSON" is not valid JSON
println("Stacktrace:")
// Stacktrace:
// Prints the full JavaScript stack trace
e.printStackTrace()
}
}
Такая обработка исключений работает автоматически в современных браузерах, поддерживающих возможность WebAssembly.JSTag:
Chrome 115+
Firefox 129+
Safari 18.4+
Отличия взаимодействия Kotlin/Wasm и Kotlin/JS
Несмотря на сходство взаимодействия в Kotlin/Wasm и Kotlin/JS, следует учитывать несколько ключевых отличий:
Kotlin/Wasm |
Kotlin/JS |
|
|---|---|---|
Внешние перечисления |
Не поддерживает внешние классы перечислений. |
Поддерживает внешние классы перечислений. |
Расширение типов |
Не поддерживает расширение внешних типов невнешними типами. |
Поддерживает невнешние типы. |
Аннотация |
Действует только при применении к внешним объявлениям. |
Можно использовать для изменения имен обычных невнешних объявлений. |
Функция |
Вызовы функции |
Функцию |
Модульные системы |
Поддерживает только ES-модули. Аналога аннотации |
Поддерживает ES-модули и устаревшие модульные системы. Предоставляет именованные экспорты ESM. Позволяет экспортировать классы и объекты. |
Типы |
Ко всем объявлениям взаимодействия |
В объявлениях |
Long |
Тип соответствует типу JavaScript |
В JavaScript отображается как пользовательский класс. |
Массивы |
Пока напрямую не поддерживаются при взаимодействии. Вместо них можно использовать новый тип |
Реализованы как массивы JavaScript. |
Другие типы |
Для передачи объектов Kotlin в JavaScript требуется |
Внешние объявления могут использовать типы невнешних классов Kotlin. |
Обработка исключений |
Можно перехватить любое исключение JavaScript с помощью типов |
Исключения JavaScript |
Динамические типы |
Тип |
Тип |
Браузерные API для веб-разработки
Библиотека kotlinx-browser — это отдельная библиотека, предоставляющая браузерные API JavaScript, включая:
-
Пакет
org.khronos.webgl:Типизированные массивы, например
Int8Array.Типы WebGL.
-
Пакеты
org.w3c.dom.*:Типы DOM API.
-
Пакет
kotlinx.browser:Глобальные объекты DOM API, например
windowиdocument.
Чтобы использовать объявления из библиотеки kotlinx-browser, добавьте её как зависимость в файл конфигурации сборки проекта:
val wasmJsMain by getting {
dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-browser:0.3")
}
}
© 2010–2026 JetBrains s.r.o. and Kotlin Programming Language contributors
Licensed under the Apache License, Version 2.0.
https://kotlinlang.org/docs/wasm-js-interop.html