Использование кода Kotlin из JavaScript
В зависимости от выбранной системы модулей JavaScript компилятор Kotlin/JS генерирует разные выходные данные. Но в целом компилятор Kotlin генерирует обычные классы, функции и свойства JavaScript, которые можно свободно использовать в коде JavaScript. Однако следует помнить о некоторых нюансах.
Изоляция объявлений в отдельном объекте JavaScript в режиме Plain
Если вы явно задали тип модуля plain, Kotlin создаёт объект, содержащий все объявления Kotlin из текущего модуля. Это сделано для того, чтобы не засорять глобальный объект. Это означает, что для модуля myModule все объявления доступны JavaScript через объект myModule. Например:
fun foo() = "Hello"
Эту функцию можно вызвать из JavaScript следующим образом:
alert(myModule.foo());
Такой прямой вызов функции неприменим, если вы компилируете модуль Kotlin в модули JavaScript, например UMD (настройка по умолчанию для целей browser и nodejs), ESM, CommonJS или AMD. В таких случаях объявления экспортируются в соответствии с выбранной системой модулей JavaScript. Например, при использовании UMD, ESM или CommonJS место вызова будет выглядеть так:
alert(require('myModule').foo());
Дополнительные сведения о системах модулей JavaScript см. в разделе Модули JavaScript.
Структура пакетов
Для большинства систем модулей (CommonJS, Plain и UMD) Kotlin предоставляет JavaScript структуру пакетов. Если вы не определяете объявления в корневом пакете, в JavaScript необходимо использовать полные имена. Например:
package my.qualified.packagename fun foo() = "Hello"
Например, при использовании UMD или CommonJS место вызова может выглядеть так:
alert(require('myModule').my.qualified.packagename.foo())
При использовании plain в качестве настройки системы модулей место вызова будет выглядеть так:
alert(myModule.my.qualified.packagename.foo());
При компиляции в модули ECMAScript (ESM) информация о пакетах не сохраняется, чтобы уменьшить размер пакета приложения и соответствовать типичной структуре пакетов ESM. В этом случае использование объявлений Kotlin с модулями ES выглядит так:
import { foo } from 'myModule';
alert(foo());
@JsName аннотация
В некоторых случаях (например, для поддержки перегрузок) компилятор Kotlin изменяет имена сгенерированных функций и атрибутов в коде JavaScript. Чтобы управлять сгенерированными именами, можно использовать аннотацию @JsName:
// Module 'kjs'
class Person(val name: String) {
fun hello() {
println("Hello $name!")
}
@JsName("helloWithGreeting")
fun hello(greeting: String) {
println("$greeting $name!")
}
}
Теперь этот класс можно использовать из JavaScript следующим образом:
// If necessary, import 'kjs' according to chosen module system
var person = new kjs.Person("Dmitry"); // refers to module 'kjs'
person.hello(); // prints "Hello Dmitry!"
person.helloWithGreeting("Servus"); // prints "Servus Dmitry!"
Если бы мы не указали аннотацию @JsName, имя соответствующей функции содержало бы суффикс, вычисленный на основе сигнатуры функции, например hello_61zpoe$.
Обратите внимание, что в некоторых случаях компилятор Kotlin не изменяет имена:
Имена объявлений
externalне изменяются.Имена всех переопределённых функций в классах, не являющихся
externalи наследующих классыexternal, не изменяются.
Параметр @JsName должен быть константной строкой, содержащей допустимый идентификатор. Компилятор сообщит об ошибке при любой попытке передать в @JsName строку, не являющуюся идентификатором. Следующий пример приведёт к ошибке компиляции:
@JsName("new C()") // error here
external fun newC()
@JsExport аннотация
Применив аннотацию @JsExport к объявлению верхнего уровня (например, классу, интерфейсу или функции), можно сделать объявления Kotlin доступными из JavaScript или TypeScript. Аннотация экспортирует все вложенные объявления под именами, заданными в Kotlin.
Вот пример экспорта интерфейса Kotlin с вложенным классом и именованным сопутствующим объектом:
@JsExport
interface Identity {
class Metadata(val tag: String)
companion object Registry {
val defaultTag = "GUEST"
}
}
В настоящее время аннотация @JsExport — единственный способ сделать ваши функции видимыми из Kotlin.
Аннотация @JsExport также доступна:
В общем коде многоплатформенных проектов. Она действует только при компиляции для целевой платформы JavaScript и позволяет также экспортировать объявления Kotlin, не относящиеся к конкретной платформе.
Вместе с аннотацией
@JsNameдля задания имён сгенерированных и экспортируемых функций. Это помогает устранить неоднозначность при экспорте (например, перегрузок функций с одинаковыми именами).На уровне файла с помощью
@file:JsExport.
Экспорт классов-значений
Классы встраиваемых значений Kotlin можно экспортировать как обычные классы TypeScript.
Чтобы экспортировать класс-значение, пометьте его аннотацией @JsExport в Kotlin:
// Kotlin
@JsExport
@JvmInline
value class Email(val address: String) {
init { require(address.contains("@")) { "Invalid email" } }
}
@JsExport
class AuthService {
suspend fun login(email: Email): String = ...
}
В TypeScript он выглядит как обычный класс:
// TypeScript
import { AuthService, Email } from "..."
const auth = new AuthService();
console.log(await auth.login(new Email("jane@example.com")));
// "Welcome, jane@example.com!"
console.log(await auth.login(new Email("not-an-email")));
// "Invalid email"
Экспорт приостанавливающих лямбда-выражений
Приостанавливающие лямбда-выражения Kotlin можно экспортировать как JavaScript асинхронные функции:
-
Чтобы включить эту функцию, добавьте следующий параметр компилятора в файл
build.gradle.kts:kotlin { js { compilations.all { compileTaskProvider.configure { compilerOptions { freeCompilerArgs.add("-Xsuspend-lambda-exporting") } } } } } -
Пометьте соответствующие объявления Kotlin аннотацией
@JsExport:// Kotlin @JsExport class TaskRunner { suspend fun runTask(task: suspend () -> String): String { return task() } } -
В TypeScript лямбда-выражение
suspendбудет преобразовано в обычную функциюasync:// TypeScript import { TaskRunner } from "..." const runner = new TaskRunner(); const result = await runner.runTask(async () => "done"); console.log(result); // "done"
@JsNoRuntime аннотация
Интерфейсы Kotlin можно экспортировать в JavaScript/TypeScript с помощью аннотации @JsNoRuntime. Она позволяет напрямую преобразовывать их в обычные интерфейсы TypeScript.
Например, чтобы экспортировать интерфейс Kotlin из многоплатформенного проекта Kotlin:
-
Пометьте интерфейс Kotlin аннотацией
@JsNoRuntimeв общем коде:// commonMain import kotlin.js.JsNoRuntime @JsNoRuntime expect interface DataProcessor { fun process(data: String): Int } -
Предоставьте фактическую реализацию с помощью
@JsNoRuntimeв исходном коде для JS:// jsMain import kotlin.js.JsNoRuntime @JsNoRuntime actual interface DataProcessor { actual fun process(data: String): Int } -
В TypeScript интерфейс будет преобразован в обычный интерфейс TypeScript:
// Generated .d.ts export interface DataProcessor { process(data: string): number; }
Для многоплатформенных проектов Kotlin действуют следующие общие правила:
Объявления интерфейсов
expectиactualдолжны быть помечены аннотацией@JsNoRuntime. Исключение составляют реализацииexternalв платформенном коде на сторонеactual, которые не требуют аннотации.Использовать объявления интерфейсов
externalв общем коде на сторонеexpectзапрещено. Вместо этого используйте обычные интерфейсы, помеченные аннотацией@JsNoRuntime.
Экспорт интерфейсов Kotlin с помощью @JsNoRuntime имеет некоторые ограничения. Аннотацию нельзя использовать с:
Интерфейсами
external, поскольку по умолчанию они уже ведут себя так, как если бы у них была аннотация@JsNoRuntime. Её добавление приводит к предупреждению компилятора.Проверками типов
isиas.Ссылками на классы с использованием синтаксиса
::class.Интерфейсами, передаваемыми как аргумент реифицированного типа.
@JsStatic
Аннотация @JsStatic указывает компилятору сгенерировать дополнительные статические методы для целевого объявления. Это позволяет напрямую использовать статические члены из кода Kotlin в JavaScript.
Аннотацию @JsStatic можно применять к функциям, определённым в именованных объектах, а также в сопутствующих объектах, объявленных внутри классов и интерфейсов. При использовании этой аннотации компилятор сгенерирует как статический метод объекта, так и метод экземпляра в самом объекте. Например:
// Kotlin
class C {
companion object {
@JsStatic
fun callStatic() {}
fun callNonStatic() {}
}
}
Теперь функция callStatic() является статической в JavaScript, а функция callNonStatic() — нет:
// JavaScript C.callStatic(); // Works, accessing the static function C.callNonStatic(); // Error, not a static function in the generated JavaScript C.Companion.callStatic(); // Instance method remains C.Companion.callNonStatic(); // The only way it works
Аннотацию @JsStatic также можно применить к свойству объекта или сопутствующего объекта. В этом случае его методы получения и установки становятся статическими членами этого объекта или класса, содержащего сопутствующий объект.
Эта функция находится на стадии экспериментальной разработки. Оставляйте отзывы в нашем трекере задач YouTrack.
Использование типа BigInt для представления типа Long в Kotlin
При компиляции в современный JavaScript (ES2020) Kotlin/JS использует встроенный тип BigInt JavaScript для представления значений Long Kotlin.
Чтобы включить поддержку типа BigInt, добавьте следующий параметр компилятора в файл build.gradle(.kts):
// build.gradle.kts
kotlin {
js {
...
compilerOptions {
freeCompilerArgs.add("-Xes-long-as-bigint")
}
}
}
Эта функция находится на стадии экспериментальной разработки. Оставляйте отзывы в нашем трекере задач YouTrack.
Использование Long в экспортируемых объявлениях
Поскольку тип Long в Kotlin может компилироваться в тип BigInt в JavaScript, Kotlin/JS поддерживает экспорт значений Long в JavaScript.
Чтобы включить эту функцию:
-
Разрешите экспорт
Longв Kotlin/JS. Добавьте следующий параметр компилятора в атрибутfreeCompilerArgsфайлаbuild.gradle(.kts):// build.gradle.kts kotlin { js { ... compilerOptions { freeCompilerArgs.add("-XXLanguage:+JsAllowLongInExportedDeclarations") } } } Включите тип
BigInt. Инструкции см. в разделе Использование типаBigIntдля представления типаLongв Kotlin.
Использование типа BigInt64Array для представления типа LongArray в Kotlin
При компиляции в JavaScript Kotlin/JS может использовать встроенный тип BigInt64Array JavaScript для представления значений LongArray в Kotlin.
Чтобы включить поддержку типа BigInt64Array, добавьте следующий параметр компилятора в файл build.gradle(.kts):
// build.gradle.kts
kotlin {
js {
...
compilerOptions {
freeCompilerArgs.add("-Xes-long-as-bigint")
}
}
}
Эта функция находится на стадии экспериментальной разработки. Оставляйте отзывы в нашем трекере задач YouTrack.
Типы Kotlin в JavaScript
Посмотрите, как типы Kotlin преобразуются в типы JavaScript:
Kotlin |
JavaScript |
Комментарии |
|---|---|---|
|
|
|
|
|
Число представляет собой код символа. |
|
|
Необходимо настроить параметр компилятора |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Имеет свойство |
|
|
|
|
|
|
|
|
|
|
|
Имеет свойство |
|
|
Предоставляет |
|
|
Предоставляет |
|
|
Предоставляет |
|
Undefined |
Можно экспортировать в качестве возвращаемого типа, но не в качестве типа параметра. |
|
|
|
|
|
|
|
|
Элементы перечисления доступны как статические свойства класса ( |
Nullable |
|
|
Все остальные типы Kotlin, кроме отмеченных |
Не поддерживается |
Включает беззнаковые целочисленные типы Kotlin. |
Кроме того, важно знать следующее:
Kotlin сохраняет семантику переполнения для
kotlin.Int,kotlin.Byte,kotlin.Short,kotlin.Charиkotlin.Long.-
Kotlin не может различать числовые типы во время выполнения (за исключением
kotlin.Long), поэтому следующий код работает:fun f() { val x: Int = 23 val y: Any = x println(y as Float) } Kotlin сохраняет отложенную инициализацию объектов в JavaScript.
© 2010–2026 JetBrains s.r.o. and Kotlin Programming Language contributors
Licensed under the Apache License, Version 2.0.
https://kotlinlang.org/docs/js-to-kotlin-interop.html