Spec-Zone.ru › Kotlin 2

Взаимодействие с JavaScript

Kotlin/Wasm позволяет использовать код JavaScript в Kotlin, а код Kotlin — в JavaScript.

Как и в Kotlin/JS, компилятор Kotlin/Wasm поддерживает взаимодействие с JavaScript. Если вы знакомы с взаимодействием в Kotlin/JS, то заметите, что взаимодействие в Kotlin/Wasm устроено похожим образом. Однако есть ключевые отличия, которые следует учитывать.

Kotlin/Wasm находится в статусе бета-версии. Он может измениться в любой момент. Используйте его в сценариях до перехода в production. Мы будем признательны за ваши отзывы в YouTrack.

Использование кода 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")
}

Аннотация @nativeInvoke — временное решение, пока не разработан стабильный механизм взаимодействия. В настоящее время при использовании @nativeInvoke компилятор выдает предупреждение.

Функции 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.

Аннотация @JsFun выполняет похожую функцию и, вероятно, будет объявлена устаревшей.

Модули 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()
    }
}

Генерация файлов объявлений TypeScript в Kotlin/Wasm является экспериментальной возможностью. Она может быть удалена или изменена в любой момент.

Соответствие типов

В сигнатурах объявлений взаимодействия с JavaScript в Kotlin/Wasm разрешены только определенные типы. Эти ограничения одинаково применяются к объявлениям с external, = js("code") или @JsExport.

Посмотрите, как типы Kotlin соответствуют типам JavaScript:

Kotlin

JavaScript

Byte, Short, Int, Char, UByte, UShort, UInt,

Number

Float, Double,

Number

Long, ULong,

BigInt

Boolean,

Boolean

String,

String

Unit в позиции возвращаемого значения

undefined

Тип функции, например (String) -> Int

Функция

JsAny и подтипы

Любое значение JavaScript

JsReference

Непрозрачная ссылка на объект Kotlin

Другие типы

Не поддерживаются

Также можно использовать nullable-версии этих типов.

Тип JsAny

Значения JavaScript представлены в Kotlin типом JsAny и его подтипами.

Стандартная библиотека Kotlin/Wasm предоставляет представления для некоторых из этих типов:

  • Пакет kotlin.js:

    • JsAny

    • JsBoolean, JsNumber, JsString

    • JsArray

    • Promise

Можно также создавать собственные подтипы 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

Внешние перечисления

Не поддерживает внешние классы перечислений.

Поддерживает внешние классы перечислений.

Расширение типов

Не поддерживает расширение внешних типов невнешними типами.

Поддерживает невнешние типы.

Аннотация JsName

Действует только при применении к внешним объявлениям.

Можно использовать для изменения имен обычных невнешних объявлений.

Функция js()

Вызовы функции js("code") разрешены как единственное выражение в теле функций уровня пакета.

Функцию js("code") можно вызывать в любом контексте; она возвращает значение dynamic.

Модульные системы

Поддерживает только ES-модули. Аналога аннотации @JsNonModule нет. Экспорты предоставляются как свойства объекта default. Можно экспортировать только функции уровня пакета.

Поддерживает ES-модули и устаревшие модульные системы. Предоставляет именованные экспорты ESM. Позволяет экспортировать классы и объекты.

Типы

Ко всем объявлениям взаимодействия external, = js("code") и @JsExport применяются одинаковые более строгие ограничения типов. Разрешено ограниченное число встроенных типов Kotlin и подтипов JsAny.

В объявлениях external разрешены все типы. Ограничены типы, которые можно использовать в @JsExport.

Long

Тип соответствует типу JavaScript BigInt.

В JavaScript отображается как пользовательский класс.

Массивы

Пока напрямую не поддерживаются при взаимодействии. Вместо них можно использовать новый тип JsArray.

Реализованы как массивы JavaScript.

Другие типы

Для передачи объектов Kotlin в JavaScript требуется JsReference<>.

Внешние объявления могут использовать типы невнешних классов Kotlin.

Обработка исключений

Можно перехватить любое исключение JavaScript с помощью типов JsException и Throwable.

Исключения JavaScript Error можно перехватывать с помощью типа Throwable. Любое исключение JavaScript можно перехватить с помощью типа dynamic.

Динамические типы

Тип dynamic не поддерживается. Вместо него используйте JsAny (см. пример кода ниже).

Тип dynamic поддерживается.

Динамический тип Kotlin/JS для взаимодействия с нетипизированными или слабо типизированными объектами не поддерживается в Kotlin/Wasm. Вместо типа dynamic можно использовать тип JsAny:

// Kotlin/JS
fun processUser(user: dynamic, age: Int) {
    // ...
    user.profile.updateAge(age)
    // ...
}

// Kotlin/Wasm
private fun updateUserAge(user: JsAny, age: Int): Unit =
    js("{ user.profile.updateAge(age); }")

fun processUser(user: JsAny, age: Int) {
    // ...
    updateUserAge(user, age)
    // ...
}

Браузерные 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")
    }
}
16 марта 2026 г.
Отладка кода Kotlin/WasmПоддерживаемые версии и конфигурация

© 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

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API