ネイティブコードでのJavaScriptの型
Vegaターボモジュールは、ターボモジュールのパラメーターと戻り値で、JavaScriptと相互に変換できるさまざまなネイティブ型をサポートしています。たとえば、std::stringを受け入れるターボモジュールメソッドはJavaScriptのstringを使用してJavaScriptから呼び出すことができ、引数は自動的に変換されます。同様に、std::stringを返すターボモジュールメソッドはJavaScript環境にJavaScriptのstringを返します。それらの一部は、std::stringやint32_tなどのC++の基本型です。その他はVega固有の型で、主にcom::amazon::kepler::turbomodule名前空間の一部として利用できます。
型マップ
次の表は、TypeScript型とそれに対応するC++型とのマッピングを示しています。これはcodegenツールで使用されるマッピングです。
これらの型の中にはTypeScriptの基本型には含まれないものがあり、@amazon-devices/keplerscript-turbomodule-apiからインポートする必要があります。
| TypeScript型 | ネイティブ型 |
|---|---|
string |
std::string |
number |
double |
Int32 |
int32_t |
UInt32 |
uint32_t |
Int64[1] |
int64_t |
Double |
double |
Float |
float |
boolean |
bool |
void |
void |
Array<T>, T[](同種配列)[2] |
std::vector<T> |
Array |
JSArray |
Object |
JSObject |
Promise |
Promise |
Function(パラメーター型) |
Callback |
Function (戻り値の型) |
HostCallback |
bigint |
BigInt[3] |
ArrayBuffer |
ArrayBuffer |
NativeObject |
std::shared_ptr<NativeObject> |
*JsonContainer[4] |
utils::json::JsonContainer |
[1] int64_tはNumber.MAX_SAFE_INTEGERが原因で精度が失われる可能性があります。精度が求められる大きな整数にはBigIntを使用できます。
[2] 同種配列とは、要素の型が同じ配列です。
[3] BigIntは、直接渡されるメソッドパラメーターおよび戻り値の型として、符号付きおよび符号なし64ビット整数でサポートされています。サポートされている使用方法の詳細については、BigIntを参照してください。
[4] JsonContainerは、JSObjectの欠陥が解消された後、削除される予定です。これを使用する必要がある場合は、@amazon-devices/keplerscript-turbomodule-apiからJsonContainer型を汎用Objectとしてインポートするか、次のようなカスタム型エイリアスを定義できます。
type MyJsonContainer = {myProperty: string};
注: JavaScriptのNumber.MAX_SAFE_INTEGERよりも大きい整数の場合は、ターボモジュールのパラメーターと戻り値の型として、std:: string表現を使用してください。JavaScriptおよびC++の実装では、stringをより適切な型に変換できます。
JSArray
同種(T[])配列には、std::vector<T>を使用できます。その他の配列には、JSArrayを使用できます。
JSArrayはstd::vectorで、nullポインター、boolean、さまざまなint、double、float、std::string、JSArray、JSObjectなどの多様な要素の型を受け入れます。したがって、その使用法はstd::vectorと同様です。
例
JSArray SampleTurboModule::getJSArray() {
auto jsObject = JSObject{};
auto jsArray = JSArray{};
jsArray.emplace_back(jsObject);
jsArray.emplace_back(std::string{"foo"});
jsArray.emplace_back(3.14);
return jsArray;
}
JSArray SampleTurboModule::extendJSArray(JSArray arr) {
arr.emplace_back(std::string{"新しい要素"});
return arr;
}
JSObject
JSObjectはstd::stringのキーを持つstd::mapで、nullポインター、boolean、さまざまなint、double、float、std::string、JSArray、JSObjectなどの多様な値の型を受け入れます。したがって、その使用法はstd::mapと同様です。
JSObjectには、静的なparseJsonメソッドが用意されています。parseJsonメソッドは、std::string型のJSON文字列を受け取り、同等のJSObjectを返します。
例
JSObject SampleTurboModule::getJSObject(std::string jsonContent) {
auto jsObject = JSObject::parseJson(jsonContent);
return jsObject;
}
JSObject SampleTurboModule::getJSObject() {
auto jsObject = JSObject{};
jsObject.emplace("intValue", 100);
jsObject.emplace("doubleValue", 25.1);
jsObject.emplace("boolValue", true);
jsObject.emplace("strValue", std::string{"文字列値"});
return jsObject;
}
JSObject SampleTurboModule::extendJSObject(JSObject obj) {
obj.emplace("foo", std::string{"bar"});
return obj;
}
プロキシJSObjectとJSArray
Vegaターボモジュールは、JSObject型とJSArray型に加えて、プロキシ型であるproxy::JSObjectとproxy::JSArrayをサポートしています。プロキシ型の主な機能の1つは、動的なアクセスと変更です。コピーを作成しなくても、C++コードからJavaScriptオブジェクトや配列の読み取りと書き込みを直接行うことができます。
ただし、これらのプロキシ型を使用する際に留意すべき重要な点がいくつかあります。
-
Threadに関する考慮事項:
プロキシ型はJSThreadコンテキストとターボモジュールメソッド呼び出しの範囲内で使用する必要があります。これらを保存したり、任意のThreadからアクセスしたりすることはできません。Threadの安全性チェックはデバッグモードでのみ実行されるため、マルチスレッド環境でこれらのプロキシオブジェクトを操作する場合は注意が必要です。
-
ネイティブでの構築
新しいプロキシ項目はネイティブに構築することができます。ただし、必要なJSRuntimeをターボモジュール、またはHostCallbackメソッドからメソッドパラメーターとして取得する必要があります。
警告: デフォルトのコンストラクターは使用しないでください。これらのプロキシ型デフォルトコンストラクターは、
std::tupleやstd::variantなど構造体での現在の内部使用をサポートするためにのみ維持されています。これらのデフォルトコンストラクターには依存しないでください。JSThreadコンテキストを必要とするため、将来のリリースでは削除される予定です。
JSRuntime
JSRuntime型は、JavaScriptランタイム環境を表します。これはネイティブ専用の型で、任意のターボモジュールまたはHostCallbackメソッドによってパラメーターとしてリクエストできます。これは通常、C++で新しいプロキシ項目を作成するために使用されます。
注: JSRuntimeはJSThread以外からは構築できません。
void SampleTurboModuleV2::sampleMethod(JSRuntime rt) {
// 新しいプロキシオブジェクトを作成します
auto newObject = proxy::JSObject(rt);
// プロキシ配列を作成します
auto newArray = proxy::JSArray(rt);
}
proxy::JSObject
proxy:: JSObject型を使用すると、ネイティブコードに渡すことができるJavaScriptオブジェクトを作成し、コピーを作成せずにネイティブ側からそのプロパティとメソッドに動的にアクセスして変更することができます。
注: proxy:: JSObjectへのアクセスはJSThreadコンテキストに制限されており、ターボモジュールメソッド呼び出しの範囲内で行う必要があります。Threadの安全性チェックはデバッグモードでのみ実行されます。
std::vector<proxy::JSObject> SampleTurboModuleV2::getProxyObject(JSRuntime rt, std::vector<proxy::JSObject> args) {
// 受け取ったオブジェクトからプロパティを読み込みます
auto object = args[0];
auto propertyNames = object.getPropertyNames();
for (const auto& propertyName: propertyNames) {
auto propertyValue = object.getProperty(propertyName);
if (std::holds_alternative<std::string>(propertyValue)) {
auto stringValue = std::get<std::string>(propertyValue);
TMINFO("Property " + propertyName + " = " + stringValue);
}
}
// 新しいオブジェクトを作成して返します
auto newObject = proxy::JSObject(rt);
newObject.setProperty("stringProp", "foo");
newObject.setProperty("numberProp", 1.5);
newObject.setProperty("boolProp", true);
args[0] = newObject;
return args;
}
proxy::JSArray
proxy::JSArray型を使用すると、ネイティブコードに渡すことができるJavaScript配列を作成し、その要素にネイティブ側から動的にアクセスして変更することができます。
注: proxy::JSArrayへのアクセスはJSThreadコンテキストに制限されており、ターボモジュールメソッド呼び出しの範囲内で行う必要があります。Threadの安全性チェックはデバッグモードでのみ実行されます。
proxy::JSArray SampleTurboModuleV2::getProxyArray(proxy::JSArray arg) {
size_t index = 0;
for(const auto& element: arg) {
if (std::holds_alternative<std::string>(element)) {
auto elementValue = std::get<std::string>(element);
TMDEBUG("SampleTurboModuleV2::getProxyArray initial string element = " + elementValue);
arg.set(index, "C++String");
}
++index;
}
return arg;
}
Promise
Promiseは別のスレッドで実行する必要があります。
Promiseは、PromiseOperationを入力として使用して作成されます。PromiseOperationは、std::shared_ptr<Promise>を受け入れ、voidを返す関数です。
Promiseには、resolveメソッドとrejectメソッドがあります。Promiseは、Errorまたはstd::stringを使用して拒否することができ、型マップに示されている任意のC++ターボモジュール型を使用して解決できます。
例
Promise<std::string> SampleTurboModule::getValueWithPromise(bool error) {
return Promise([self = this, error](const std::shared_ptr<Promise>& promise) {
std::thread([error, promise]() {
if (error) {
promise->reject(Error("promiseはErrorクラスを使用して拒否されました"));
} else {
promise->resolve(std::string{"結果"});
}
}).detach();;
});
}
Callback
コールバックは別のスレッドで実行する必要があります。
Callbackオブジェクトはパラメーター値としてのみ使用でき、C++に渡されるJavaScriptコールバックを表します。戻り値の型としてのコールバックについては、HostCallbackを参照してください。
Callbackオブジェクトは、唯一のメソッドとしてinvokeを公開します。このメソッドは、指定された引数でJavaScriptコールバックを呼び出し、結果をC++に返します。
例
// JS
SampleTurboModule.getValueWithCallback((value : number) => {
console.log(value); // C++ Callback.invokeメソッドから引数として渡された値5がログに記録されます。
return 2 * value;
});
// C++
void SampleTurboModule::getValueWithCallback(Callback callback) {
std::thread([](Callback callback) {
auto future = callback.invoke(5);
std::string returnValue{"undefined"};
try {
auto jsValue = future.get();
// JSから返される数値は常にdoubleです。
if(std::holds_alternative<double>(jsValue)) {
returnValue = std::to_string(std::get<double>(jsValue));
}
} catch (const std::exception& ex) {
TMERROR("コールバックからの戻り値の取得に失敗しました。Exception: " + std::string(ex.what()));
}
TMINFO("コールバックからの戻り値:" + returnValue);
}, callback).detach();
}
HostCallback
HostCallbackは戻り値にのみ指定でき、JavaScript環境にC++コールバックを返すために使用されます。パラメーターの型としてのコールバックについては、Callbackを参照してください。
例
// C++
std::string sampleHostCallbackMethod(std::string jsInputString) {
return "受け取ったJS文字列:" + jsInputString);
}
HostCallback SampleTurboModule::getHostCallback() {
return HostCallback(sampleHostCallbackMethod);
}
// JS
const hostCallback = SampleTurboModule.getHostCallback();
console.log(hostCallback("Hello from HostCallback!")); // prints "受け取ったJS文字列:Hello from HostCallback!"
}
HostCallbackを使用してCallbackを呼び出すこともできます。
// JS
SampleTurboModule.invokeCallbackWithHostCallback((hostCallback: (obj: Object) => number): void {
const secret = hostCallback();
console.log(secret); // 17をログに記録します
});
// C++
void SampleTurboModule::invokeCallbackWithHostCallback(Callback callback) {
auto secret = 17;
auto lambda = [secret]() {
return secret;
};
auto hostCallback = HostCallback(std::function<int()>(lambda));
callback.invoke(hostCallback);
}
ArrayBuffer
ArrayBufferは、汎用、固定長の生バイナリデータバッファーを表します。
例
ArrayBuffer SampleTurboModule::getNativeMemoryArrayBuffer() {
return {"Hello World!"};
}
ArrayBuffer SampleTurboModule::modifyArrayBuffer(ArrayBuffer buf) {
// 新しいコンテンツを挿入せずに変更するだけで、データのコピーは行いません。
uint8_t* data = buf.data();
size_t size = buf.size();
for (auto i = 0; i < size; i++) {
data[i] = 9;
}
return buf;
}
ArrayBuffer SampleTurboModule::insertSecretData(ArrayBuffer buf) {
// ここで挿入すると、データのコピーが作成されファイナライザーがアタッチされます
uint8_t secret[] = {6, 7, 9, 9, 0};
arg.insert(5, secret);
return arg;
}
BigInt
BigIntは整数を表します。JavaScriptでは、Number.MAX_SAFE_INTEGERより大きい整数またはNumber.MIN_SAFE_INTEGERより小さい整数に使用されます。Vegaでは、ターボモジュールは、int64_tおよびuint64_tベースのゲッターメソッドとコンストラクターメソッドを持つBigIntをサポートしています。
BigInt SampleTurboModule::getBigInt(BigInt bigint) {
// BigIntを作成します
auto big1 = BigInt::fromI64(-9007199254740990);
auto big2 = BigInt::fromUi64(static_cast<uint64_t>(9007199254740990));
// 値にアクセスします。ゲッターはコンストラクターの呼び出しで使用される型には依存しません。
auto asI64 = bigint.getI64();
auto asUi64 = bigint.getUi64();
// getI64()は次のプロパティを持つ構造体を返します
int64_t i64value = asI64.value;
bool lossless = asI64.lossless;
// getUi64()は次のプロパティを持つ構造体を返します
bool is_signed = asUi64.is_signed;
uint64_t ui64value = asUi64.value;
bool lossless = asUi64.lossless;
return big1;
}
BigIntは、メソッドのパラメーターや戻り値、コールバックやPromiseに使用できますが、未加工の値としてのみ使用でき、 JSArrayやJSObjectの一部としては使用できません。
JavaScriptのBigIntが大きすぎてVegaターボモジュールのBigInt型では表せない場合(たとえば、int64_tやuint64_tでは表現できない)、Vegaターボモジュールのすべての無効なパラメーターと同様に、アサーションに失敗します。詳細については、「ターボモジュールに関する高度なトピック」のエラー処理を参照してください。
utils::json::JsonContainer
JSObject型としてのJsonContainerの使用は置き換えられていますが、現時点ではまだいくつかの機能上のギャップがあります。サポートされている型の完全なリストについては、型マップを参照してください。
例
utils::json::JsonContainer SampleTurboModuleV2::getJsonContainer() {
auto result = utils::json::JsonContainer::createJsonObject();
result.insert("const1", true);
result.insert("const2", 375);
result.insert("const3", std::string("何か"));
return result;
}
NativeObject
ネイティブコードからJavaScriptにデータを渡すときに、ほとんどの場合、JSONContainerまたはJSObjectで十分です。ただし、JavaScriptからメソッドを呼び出すことができるネイティブオブジェクトが必要な場合は、com::amazon::kepler::turbomodule::NativeObjectを実装するオブジェクトを作成する必要があります。
例
#include <Vega/turbomodule/NativeObject.h>
using namespace com::amazon::kepler::turbomodule;
class SampleNativeObject : NativeObject {
public:
// JavaScriptに公開するには、この関数のmethodAggregatorにメソッドを追加する必要があります。
void aggregateMethods(MethodAggregator<NativeObject> &methodAggregator) noexcept override {
methodAggregator.addMethod("getString", 1,
&SampleNativeObjectV2::getString);
}
std::string getString(std::string arg) {
return "さようなら" + arg;
}
};
// ターボモジュール実装の場合:
std::shared_ptr<NativeObject> SampleTurboModule::getNativeObject() {
return std::make_shared<SampleNativeObject>();
}
// JavaScriptでの使用方法:
SampleTurboModule.getNativeObject().getString("foo"); // 「さようならfoo」を返します
NativeObjectはターボモジュールメソッドの戻り値の型としてのみサポートされており、パラメーターとしてはサポートされていないことに注意してください。
APMF型
IDLは一部のAPMF型を使用しますが、サポートされているターボモジュールのパラメーターや戻り値の型との間で直接変換できない場合があります。これらの変換を行うには、カスタムロジックの実装が必要になる場合があります。
関連トピック
Last updated: 2025年9月30日

