JavaScriptからKotlinコードを使用する
選択された JavaScript モジュールシステムに応じて、Kotlin/JS コンパイラは異なる出力を生成します。 しかし、一般的に Kotlin コンパイラは通常の JavaScript のクラス、関数、プロパティを生成するため、JavaScript コードから自由に利用できます。 ただし、いくつか注意すべき細かい点があります。
plain モードにおいて個別の JavaScript オブジェクトに宣言を分離する
モジュール形式を明示的に plain に設定した場合、Kotlin は現在のモジュールのすべての Kotlin 宣言を含むオブジェクトを作成します。 これはグローバルオブジェクトを汚染するのを防ぐために行われます。つまり、myModule というモジュールの場合、すべての宣言は myModule オブジェクトを介して JavaScript から利用可能になります。例えば:
fun foo() = "Hello"この関数は JavaScript から次のように呼び出すことができます:
alert(myModule.foo());コンパイルターゲットとして UMD(browser および nodejs ターゲットの両方でデフォルトの設定)、ESM、CommonJS、AMD などの JavaScript モジュールを使用する場合、このように関数を直接呼び出す手法は適用されません。 これらの場合、宣言は選択された JavaScript モジュールシステムに従って公開されます。 例えば、UMD、ESM、または CommonJS を使用する場合、呼び出し側は次のようになります:
alert(require('myModule').foo());JavaScript モジュールシステムの詳細については、JavaScript モジュールを参照してください。
パッケージ構造
ほとんどのモジュールシステム(CommonJS、Plain、UMD)において、Kotlin はそのパッケージ構造を JavaScript に公開します。 ルートパッケージ以外で宣言を定義する場合、JavaScript では完全修飾名(fully qualified names)を使用する必要があります。 例えば:
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 パッケージの典型的なレイアウトに合わせるため、パッケージ情報は保持されません。 この場合、ES モジュールでの Kotlin 宣言の利用は次のようになります:
import { foo } from 'myModule';
alert(foo());@JsName アノテーション
場合によっては(例えば、オーバーロードをサポートするため)、Kotlin コンパイラは JavaScript コード内で生成される関数や属性の名前をマングル(難読化・加工)します。 生成される名前を制御するには、@JsName アノテーションを使用できます。
// モジュール 'kjs'
class Person(val name: String) {
fun hello() {
println("Hello $name!")
}
@JsName("helloWithGreeting")
fun hello(greeting: String) {
println("$greeting $name!")
}
}これで、JavaScript からこのクラスを次のように使用できます。
// 必要に応じて、選択したモジュールシステムに従って 'kjs' をインポートしてください
var person = new kjs.Person("Dmitry"); // モジュール 'kjs' を参照
person.hello(); // "Hello Dmitry!" を出力
person.helloWithGreeting("Servus"); // "Servus Dmitry!" を出力@JsName アノテーションを指定しなかった場合、対応する関数の名前には、関数のシグネチャから計算されたサフィックス(例えば hello_61zpoe)が含まれます。
Kotlin コンパイラがマングリングを適用しないケースがいくつかあることに注意してください:
external宣言はマングルされません。externalクラスを継承した非externalクラス内のオーバーライドされた関数はマングルされません。
@JsName のパラメータは、有効な識別子である定数文字列リテラルである必要があります。 識別子ではない文字列を @JsName に渡そうとすると、コンパイラはエラーを報告します。 次の例はコンパイルエラーになります:
@JsName("new C()") // ここでエラー
external fun newC()@JsExport アノテーション
この機能は試験的です。 将来のバージョンで設計が変更される可能性があります。
トップレベルの宣言(クラスや関数など)に @JsExport アノテーションを適用することで、その Kotlin 宣言を JavaScript から利用できるようにします。このアノテーションは、Kotlin で指定された名前ですべてのネストされた宣言をエクスポートします。 また、@file:JsExport を使用してファイルレベルで適用することもできます。
エクスポートにおける曖昧さ(同名の関数のオーバーロードなど)を解決するために、@JsExport アノテーションを @JsName と組み合わせて使用し、生成およびエクスポートされる関数の名前を指定できます。
現在、@JsExport アノテーションは、Kotlin の関数を JavaScript から見えるようにするための唯一の方法です。
マルチプラットフォームプロジェクトでは、@JsExport は共通コード(common code)でも利用可能です。これは JavaScript ターゲット向けにコンパイルする場合にのみ効果があり、プラットフォーム固有ではない Kotlin 宣言もエクスポートできるようにします。
@JsStatic
この機能は試験的です。いつでも削除または変更される可能性があります。 評価目的でのみ使用してください。YouTrack でのフィードバックをお待ちしております。
@JsStatic アノテーションは、ターゲットとなる宣言に対して追加の静的メソッドを生成するようコンパイラに指示します。 これにより、Kotlin コードの静的メンバーを JavaScript で直接使用できるようになります。
@JsStatic アノテーションは、名前付きオブジェクト(named object)内で定義された関数、およびクラスやインターフェース内で宣言されたコンパニオンオブジェクト内の関数に適用できます。 このアノテーションを使用すると、コンパイラはオブジェクトの静的メソッドと、オブジェクト自体のインスタンスメソッドの両方を生成します。例えば:
// Kotlin
class C {
companion object {
@JsStatic
fun callStatic() {}
fun callNonStatic() {}
}
}これで、JavaScript において callStatic() 関数は静的になりますが、callNonStatic() 関数は静的ではありません:
// JavaScript
C.callStatic(); // 動作する。静的関数にアクセス
C.callNonStatic(); // エラー。生成された JavaScript では静的関数ではない
C.Companion.callStatic(); // インスタンスメソッドは残る
C.Companion.callNonStatic(); // これが唯一の動作する方法また、オブジェクトまたはコンパニオンオブジェクトのプロパティに @JsStatic アノテーションを適用することもでき、そのゲッターおよびセッターメソッドを、そのオブジェクトまたはコンパニオンオブジェクトを含むクラスの静的メンバーにすることができます。
Kotlin の Long 型を表現するために BigInt 型を使用する
Kotlin/JS は、モダンな JavaScript(ES2020)へコンパイルする際、Kotlin の Long 値を表現するために JavaScript の組み込みの BigInt 型を使用します。
BigInt 型のサポートを有効にするには、build.gradle(.kts) ファイルに以下のコンパイラオプションを追加する必要があります。
// build.gradle.kts
kotlin {
js {
...
compilerOptions {
freeCompilerArgs.add("-Xes-long-as-bigint")
}
}
}この機能は試験的です。課題トラッカー YouTrack でフィードバックを共有してください。
エクスポートされた宣言で Long を使用する
Kotlin の Long 型は JavaScript の BigInt 型にコンパイルできるため、Kotlin/JS は Long 値の JavaScript へのエクスポートをサポートしています。
この機能を有効にするには:
- Kotlin/JS での
Longのエクスポートを許可します。build.gradle(.kts)ファイルのfreeCompilerArgs属性に以下のコンパイラオプションを追加してください:
// build.gradle.kts
kotlin {
js {
...
compilerOptions {
freeCompilerArgs.add("-XXLanguage:+JsAllowLongInExportedDeclarations")
}
}
}BigInt型を有効にします。有効化の方法については、Kotlin の Long 型を表現するために BigInt 型を使用するを参照してください。
Kotlin の LongArray 型を表現するために BigInt64Array 型を使用する
Kotlin/JS は、JavaScript へコンパイルする際、Kotlin の LongArray 値を表現するために JavaScript の組み込みの BigInt64Array 型を使用できます。
BigInt64Array 型のサポートを有効にするには、build.gradle(.kts) ファイルに以下のコンパイラオプションを追加します。
// build.gradle.kts
kotlin {
js {
...
compilerOptions {
freeCompilerArgs.add("-Xes-long-as-bigint")
}
}
}この機能は試験的です。課題トラッカー YouTrack でフィードバックを共有してください。
JavaScript における Kotlin の型
Kotlin の型が JavaScript の型にどのようにマッピングされるかを確認してください:
| Kotlin | JavaScript | 備考 |
|---|---|---|
Byte, Short, Int, Float, Double | Number | |
Char | Number | 数値は文字コードを表します。 |
Long | BigInt | -Xes-long-as-bigint コンパイラオプションの設定が必要です。 |
Boolean | Boolean | |
String | String | |
Array | Array | |
ByteArray | Int8Array | |
ShortArray | Int16Array | |
IntArray | Int32Array | |
CharArray | UInt16Array | $type$ == "CharArray" というプロパティを持ちます。 |
FloatArray | Float32Array | |
DoubleArray | Float64Array | |
LongArray | BigInt64Array | |
BooleanArray | Int8Array | $type$ == "BooleanArray" というプロパティを持ちます。 |
List, MutableList | KtList, KtMutableList | KtList.asJsReadonlyArrayView または KtMutableList.asJsArrayView を介して Array を公開します。 |
Map, MutableMap | KtMap, KtMutableMap | KtMap.asJsReadonlyMapView または KtMutableMap.asJsMapView を介して ES2015 の Map を公開します。 |
Set, MutableSet | KtSet, KtMutableSet | KtSet.asJsReadonlySetView または KtMutableSet.asJsSetView を介して ES2015 の Set を公開します。 |
Unit | Undefined | 戻り値の型として使用される場合はエクスポート可能ですが、パラメータの型として使用される場合はエクスポートできません。 |
Any | Object | |
Throwable | Error | |
enum class Type | Type | Enum エントリは、クラスの静的プロパティ(Type.ENTRY)として公開されます。 |
Nullable Type? | `Type | null |
@JsExport が付いていないその他のすべての Kotlin 型 | サポートされていません | Kotlin の 符号なし整数型を含みます。 |
さらに、以下の点を知っておくことが重要です:
Kotlin は
kotlin.Int、kotlin.Byte、kotlin.Short、kotlin.Char、kotlin.Longに対してオーバーフローのセマンティクスを保持します。Kotlin は実行時に(
kotlin.Longを除き)数値型を区別できないため、以下のコードは動作します:kotlinfun f() { val x: Int = 23 val y: Any = x println(y as Float) }Kotlin は JavaScript においてもオブジェクトの遅延初期化(lazy initialization)を保持します。
