Skip to content

JavaScriptからKotlinコードを使用する

選択された JavaScript モジュールシステムに応じて、Kotlin/JS コンパイラは異なる出力を生成します。 しかし、一般的に Kotlin コンパイラは通常の JavaScript のクラス、関数、プロパティを生成するため、JavaScript コードから自由に利用できます。 ただし、いくつか注意すべき細かい点があります。

plain モードにおいて個別の JavaScript オブジェクトに宣言を分離する

モジュール形式を明示的に plain に設定した場合、Kotlin は現在のモジュールのすべての Kotlin 宣言を含むオブジェクトを作成します。 これはグローバルオブジェクトを汚染するのを防ぐために行われます。つまり、myModule というモジュールの場合、すべての宣言は myModule オブジェクトを介して JavaScript から利用可能になります。例えば:

kotlin
fun foo() = "Hello"

この関数は JavaScript から次のように呼び出すことができます:

javascript
alert(myModule.foo());

コンパイルターゲットとして UMDbrowser および nodejs ターゲットの両方でデフォルトの設定)、ESMCommonJSAMD などの JavaScript モジュールを使用する場合、このように関数を直接呼び出す手法は適用されません。 これらの場合、宣言は選択された JavaScript モジュールシステムに従って公開されます。 例えば、UMD、ESM、または CommonJS を使用する場合、呼び出し側は次のようになります:

javascript
alert(require('myModule').foo());

JavaScript モジュールシステムの詳細については、JavaScript モジュールを参照してください。

パッケージ構造

ほとんどのモジュールシステム(CommonJS、Plain、UMD)において、Kotlin はそのパッケージ構造を JavaScript に公開します。 ルートパッケージ以外で宣言を定義する場合、JavaScript では完全修飾名(fully qualified names)を使用する必要があります。 例えば:

kotlin
package my.qualified.packagename

fun foo() = "Hello"

例えば、UMD や CommonJS を使用する場合、呼び出し側は次のようになります:

javascript
alert(require('myModule').my.qualified.packagename.foo())

モジュールシステムの設定として plain を使用している場合、呼び出し側は次のようになります:

javascript
alert(myModule.my.qualified.packagename.foo());

ECMAScript モジュール(ESM)をターゲットにする場合、アプリケーションのバンドルサイズを改善し、ESM パッケージの典型的なレイアウトに合わせるため、パッケージ情報は保持されません。 この場合、ES モジュールでの Kotlin 宣言の利用は次のようになります:

javascript
import { foo } from 'myModule';

alert(foo());

@JsName アノテーション

場合によっては(例えば、オーバーロードをサポートするため)、Kotlin コンパイラは JavaScript コード内で生成される関数や属性の名前をマングル(難読化・加工)します。 生成される名前を制御するには、@JsName アノテーションを使用できます。

kotlin
// モジュール 'kjs'
class Person(val name: String) {
    fun hello() {
        println("Hello $name!")
    }

    @JsName("helloWithGreeting")
    fun hello(greeting: String) {
        println("$greeting $name!")
    }
}

これで、JavaScript からこのクラスを次のように使用できます。

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 に渡そうとすると、コンパイラはエラーを報告します。 次の例はコンパイルエラーになります:

kotlin
@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
// Kotlin
class C {
    companion object {
        @JsStatic
        fun callStatic() {}
        fun callNonStatic() {}
    }
}

これで、JavaScript において callStatic() 関数は静的になりますが、callNonStatic() 関数は静的ではありません:

javascript
// JavaScript
C.callStatic();              // 動作する。静的関数にアクセス
C.callNonStatic();           // エラー。生成された JavaScript では静的関数ではない
C.Companion.callStatic();    // インスタンスメソッドは残る
C.Companion.callNonStatic(); // これが唯一の動作する方法

また、オブジェクトまたはコンパニオンオブジェクトのプロパティに @JsStatic アノテーションを適用することもでき、そのゲッターおよびセッターメソッドを、そのオブジェクトまたはコンパニオンオブジェクトを含むクラスの静的メンバーにすることができます。

Experimental

Kotlin の Long 型を表現するために BigInt 型を使用する

Kotlin/JS は、モダンな JavaScript(ES2020)へコンパイルする際、Kotlin の Long 値を表現するために JavaScript の組み込みの BigInt 型を使用します。

BigInt 型のサポートを有効にするには、build.gradle(.kts) ファイルに以下のコンパイラオプションを追加する必要があります。

kotlin
// build.gradle.kts
kotlin {
    js {
        ...
        compilerOptions {
            freeCompilerArgs.add("-Xes-long-as-bigint")
        }
    }
}

この機能は試験的です。課題トラッカー YouTrack でフィードバックを共有してください。

エクスポートされた宣言で Long を使用する

Kotlin の Long 型は JavaScript の BigInt 型にコンパイルできるため、Kotlin/JS は Long 値の JavaScript へのエクスポートをサポートしています。

この機能を有効にするには:

  1. Kotlin/JS での Long のエクスポートを許可します。build.gradle(.kts) ファイルの freeCompilerArgs 属性に以下のコンパイラオプションを追加してください:
kotlin
// build.gradle.kts
kotlin {
   js {
       ...
       compilerOptions { 
           freeCompilerArgs.add("-XXLanguage:+JsAllowLongInExportedDeclarations")
       }
   }
}
  1. BigInt 型を有効にします。有効化の方法については、Kotlin の Long 型を表現するために BigInt 型を使用するを参照してください。
Experimental

Kotlin の LongArray 型を表現するために BigInt64Array 型を使用する

Kotlin/JS は、JavaScript へコンパイルする際、Kotlin の LongArray 値を表現するために JavaScript の組み込みの BigInt64Array 型を使用できます。

BigInt64Array 型のサポートを有効にするには、build.gradle(.kts) ファイルに以下のコンパイラオプションを追加します。

kotlin
// build.gradle.kts
kotlin {
    js {
        ...
        compilerOptions {
            freeCompilerArgs.add("-Xes-long-as-bigint")
        }
    }
}

この機能は試験的です。課題トラッカー YouTrack でフィードバックを共有してください。

JavaScript における Kotlin の型

Kotlin の型が JavaScript の型にどのようにマッピングされるかを確認してください:

KotlinJavaScript備考
Byte, Short, Int, Float, DoubleNumber
CharNumber数値は文字コードを表します。
LongBigInt-Xes-long-as-bigint コンパイラオプションの設定が必要です。
BooleanBoolean
StringString
ArrayArray
ByteArrayInt8Array
ShortArrayInt16Array
IntArrayInt32Array
CharArrayUInt16Array$type$ == "CharArray" というプロパティを持ちます。
FloatArrayFloat32Array
DoubleArrayFloat64Array
LongArrayBigInt64Array
BooleanArrayInt8Array$type$ == "BooleanArray" というプロパティを持ちます。
List, MutableListKtList, KtMutableListKtList.asJsReadonlyArrayView または KtMutableList.asJsArrayView を介して Array を公開します。
Map, MutableMapKtMap, KtMutableMapKtMap.asJsReadonlyMapView または KtMutableMap.asJsMapView を介して ES2015 の Map を公開します。
Set, MutableSetKtSet, KtMutableSetKtSet.asJsReadonlySetView または KtMutableSet.asJsSetView を介して ES2015 の Set を公開します。
UnitUndefined戻り値の型として使用される場合はエクスポート可能ですが、パラメータの型として使用される場合はエクスポートできません。
AnyObject
ThrowableError
enum class TypeTypeEnum エントリは、クラスの静的プロパティ(Type.ENTRY)として公開されます。
Nullable Type?`Typenull
@JsExport が付いていないその他のすべての Kotlin 型サポートされていませんKotlin の 符号なし整数型を含みます。

さらに、以下の点を知っておくことが重要です:

  • Kotlin は kotlin.Intkotlin.Bytekotlin.Shortkotlin.Charkotlin.Long に対してオーバーフローのセマンティクスを保持します。

  • Kotlin は実行時に(kotlin.Long を除き)数値型を区別できないため、以下のコードは動作します:

    kotlin
    fun f() {
        val x: Int = 23
        val y: Any = x
        println(y as Float)
    }
  • Kotlin は JavaScript においてもオブジェクトの遅延初期化(lazy initialization)を保持します。