Spec-Zone.ru › Kotlin 1.9

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

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

Компилятор Kotlin/JS уже предоставляет возможность транспилировать ваш код Kotlin в JavaScript. Взаимодействие Kotlin/Wasm с JavaScript разработано аналогичным образом, учитывая, что JavaScript — язык динамической типизации, в отличие от Kotlin. Следуйте нашему руководству, чтобы настроить взаимодействие в ваших проектах.

Помните, что Kotlin/Wasm всё ещё экспериментальный, и некоторые функции ещё не поддерживаются. Мы планируем улучшить взаимодействие с JavaScript, реализовав некоторые недостающие функции или аналогичную функциональность.

Использование кода JavaScript из Kotlin

Модификатор external

Для доступа к объявлениям JavaScript, определённым в глобальной области видимости, пометьте их модификатором external. Рассмотрим этот пример кода JavaScript:

// JavaScript

function consoleLogExample() {
    console.log("Hello");
}

let externalInt = 0;

let Counter = {
    value: 0,
    step: 1,
    increment() {
        this.value += this.step;
    }
};

class Rectangle {
    constructor(height, width) {
        this.height = height;
        this.width = width;
    }

    get area() {
        return this.calcArea();
    }

    calcArea() {
        return this.height * this.width;
    }
}

Вот как вы можете использовать этот код JavaScript в Kotlin:

// Kotlin/Wasm

// Use external functions to call JS functions defined in global scope
external fun consoleLogExample(): Unit

// In addition to functions, you can have external top-level properties
external var externalInt: Int

// External objects
external object Counter {
    fun increment(): Unit
    val value: Int
    var step: Int
}

// External class
external class Rectangle(height: Double, width: Double) {
    val height: Double
    val width: Double
    val area: Double
    fun calcArea(): Double
}

Полный код см. в примере проекта Kotlin/Wasm браузер.

Некоторые функции "external" Kotlin/JS не поддерживаются в Kotlin/Wasm:

  • Реализация или расширение внешних типов

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

Аннотация @JsFun

Для включения небольшого фрагмента кода JS в ваш модуль Kotlin/Wasm используйте аннотацию @JsFun с внешними функциями верхнего уровня. Аргумент аннотации должен быть строкой с кодом JS, который вычисляет функцию с соответствующей сигнатурой:

@JsFun("function count(x) { return x + 10; }")
external fun count(x: Int): Int

Для краткости используйте синтаксис со стрелками:

@JsFun("x => x + 10")
external fun count(x: Int): Int

Компилятор Kotlin не проверяет эти фрагменты кода JavaScript и вычисляет их как есть. Синтаксические ошибки, если они есть, будут сообщены при выполнении вашего JavaScript.

Эти выражения функций вычисляются только один раз, до загрузки модуля Wasm. Не полагайтесь на побочные эффекты, поскольку эти выражения не выполняются, если функция не вызывается.

@JsModule

Чтобы указать, что класс, пакет, функция или свойство external является модулем JavaScript, используйте @JsModule аннотацию. Рассмотрим этот пример кода JavaScript:

// jsModule.mjs
let maxUsers = 10;

function getActiveUsers() {
    return 10;
};

class User {
    constructor(maxUsers) {
        this.maxUsers = maxUsers;
    }
}

export {maxUsers, getActiveUsers, User};

Вот как вы можете использовать этот код JavaScript в Kotlin:

// kotlin
@file:JsModule("./jsModule.mjs")

package example

external val maxUsers: Int
external fun getActiveUsers(): Int
external class User {
    constructor(username: String)
    val username : String
}

Kotlin/Wasm поддерживает только модули ES. Поэтому вы не можете использовать аннотацию @JsNonModule.

Использование кода Kotlin из JavaScript

Аннотация @JsExport

Чтобы сделать объявление Kotlin/Wasm доступным из JavaScript, используйте аннотацию @JsExport с внешними функциями верхнего уровня:

// Kotlin/Wasm

@JsExport
fun addOne(x: Int): Int = x + 1

Теперь вы можете использовать эту функцию из JavaScript следующим образом:

// JavaScript

import exports from "module.mjs"
exports.addOne(10)

Функции, помеченные аннотацией @JsExport, отображаются как свойства в default экспорте сгенерированного .mjs модуля. Kotlin типы в JavaScript В Kotlin/JS значения реализуются внутренне как примитивы и объекты JavaScript. Они передаются в JavaScript и из него без обертки или копирования.

Однако в Kotlin/Wasm объекты имеют другое представление и не взаимозаменяемы с JavaScript. При передаче объекта Kotlin в JavaScript он по умолчанию рассматривается как пустой непрозрачный объект.

Единственное, что вы можете сделать, это сохранить его и передать объекты Kotlin обратно в Wasm. Однако для примитивных типов Kotlin/Wasm может адаптировать эти значения, чтобы они были полезны в JavaScript, путем копирования или обертки. Для повышения эффективности это делается статически. Важно, чтобы эти специальные конкретные типы присутствовали в сигнатурах функций. Например:

external fun convertIntAndString(num: Int, text: String)
external fun convertAnyAndChars(num: Any, text: CharSequence)

// ...

convertIntAndString(10, "Hello") // Converts Int and String to JS Number and String

convertAnyAndChars(10, "Hello") // No conversion
                                // values are passed as opaque references to Wasm objects

Типы Kotlin в JavaScript

Поддерживаемые типы

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

Kotlin

JavaScript

Комментарии

Byte, Short, Int, Char

Number

Float, Double

Number

Long

BigInt

Boolean

Boolean

String

String

Содержимое строки копируется. В будущем предложение stringref может позволить нулевую копию взаимодействия строк.

Unit

Неопределено

Только при не-nullable и в функциях, возвращающих позицию.

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

Ссылка на функцию

Параметры и возвращаемые значения типов функций следуют тем же правилам преобразования типов.

external interface

Любое JS значение с заданными свойствами

external class или external object

Соответствующий JS класс

Другие типы Kotlin

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

Сюда входят типы Any, массивы, класс Throwable, коллекции и т. д.

Nullable Type?

Тип / null / undefined

Параметры типа <T : U>

Тот же, что и верхняя граница

В объявлениях взаимодействия поддерживаются только внешние типы, такие как JsAny, в качестве верхних границ параметров типа.

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

Выражение Kotlin/Wasm try-catch не может перехватывать исключения JavaScript.

Если вы попытаетесь использовать JavaScript try-catch выражение для перехвата исключений Kotlin/Wasm, оно будет выглядеть как общее WebAssembly.Exception без прямого доступа к сообщениям и данным.

Обходные пути для функций Kotlin/JS, не поддерживаемых в Kotlin/Wasm

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

Kotlin/JS динамический тип, используемый для взаимодействия с неопределёнными или слабо типизированными объектами, пока не поддерживается. Во многих случаях можно использовать внешние интерфейсы и аннотацию @JsFun вместо этого:

// Kotlin/JS

val user: dynamic
val age: Int = 0
user.profile.updateAge(age);

// Kotlin/Wasm

external interface User

@JsFun("(user, age) => user.profile.updateAge(age)")
external fun updateUserAge(user: User, age: Int)

val user: User
val age: Int = 0
updateUserAge(user, age);

Встраивание JavaScript

Функция js(), используемая для встраивания кода JavaScript в код Kotlin, пока не поддерживается. Используйте аннотацию @JsFun вместо этого:

// Kotlin/JS

fun jsTypeOf(obj: Any): String {
    return js("typeof obj")
}

// Kotlin/Wasm
@JsFun("(obj) => typeof obj")
external fun jsTypeOf(obj: SomeExternalInterfaceType): String

Расширение внешних интерфейсов и классов не внешними классами

Расширение классов JavaScript и использование внешних интерфейсов пока не поддерживается. Используйте аннотацию @JsFun вместо этого:

external interface DataProcessor {
    fun processData(input: String): String
    fun processResult(input: String): String
}

class DataHandler(val handlerData: String) {
    fun processData(input: String): String = input + handlerData
    fun processResult(input: String): String = handlerData + input
}

@JsFun("(processData, processResult) => ({ processData, processResult })")
external fun createDataProcessor(
    processData: (String) -> String,
    processResult: (String) -> String
): DataProcessor

fun convertHandlerToProcessor(handler: DataHandler): DataProcessor =
    createDataProcessor(
        processData = { input -> handler.processData(input) },
        processResult = { input -> handler.processResult(input) }
    )
Последнее изменение: 07 июня 2023 г.
Добавление зависимостей от библиотек Kotlin в проект Kotlin/Wasm Настройка проекта Kotlin/JS

© 2010–2023 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