JS型
Dart値とJS値は、別々の言語ドメインに属します。Wasmにコンパイルする場合、別々のランタイムでも実行されます。そのため、JS値は外部型として扱う必要があります。JS値にDart型を提供するために、dart:js_interop
は、JS
で始まる「JS型」と呼ばれる一連の型を公開しています。これらの型は、コンパイル時にDart値とJS値を区別するために使用されます。
重要な点として、これらの型はWasmまたはJSにコンパイルするかどうかによって、異なる方法で具象化されます。つまり、ランタイム型が異なり、そのためis
チェックとas
キャストを使用することはできません。これらのJS値を操作して調べるには、external
インターオプメンバーまたは変換を使用する必要があります。
型階層
#JS型は自然な型階層を形成します。
- 最上位型:
JSAny
(null以外のJS値)- プリミティブ:
JSNumber
、JSBoolean
、JSString
JSSymbol
JSBigInt
JSObject
(任意のJSオブジェクト)JSFunction
JSExportedDartFunction
(JS関数に変換されたDartコールバックを表す)
JSArray
JSPromise
JSDataView
JSTypedArray
JSUint8Array
などのJS型付き配列
JSBoxedDartObject
(ユーザーがDart値を同じDartランタイム内で不透明にボックス化して渡すことを許可する)- Dart 3.4以降、
dart:js_interop
のExternalDartReference
型も、ユーザーがDart値を不透明に渡すことを許可しますが、JS型ではありません。各オプションのトレードオフの詳細についてはこちらをご覧ください。
- Dart 3.4以降、
- プリミティブ:
dart:js_interop
APIドキュメントで、各型の定義を確認できます。
変換
#一方のドメインからもう一方のドメインの値を使用するには、値をもう一方のドメインの対応する型に変換する必要があるでしょう。たとえば、Dart List<JSString>
をJSインターオプAPIに渡せるように、JS文字列のJS配列(JS型JSArray<JSString>
で表される)に変換したい場合があります。
Dartは、さまざまなDart型とJS型で、値をドメイン間で変換するための多くの変換メンバーを提供しています。
DartからJSへの値を変換するメンバーは、通常toJS
で始まります。
String str = 'hello world';
JSString jsStr = str.toJS;
JSからDartへの値を変換するメンバーは、通常toDart
で始まります。
JSNumber jsNum = ...;
int integer = jsNum.toDartInt;
すべてのJS型に変換があるわけではなく、すべてのDart型に変換があるわけではありません。一般的に、変換表は次のようになります。
dart:js_interop 型 | Dart型 |
---|---|
JSNumber 、JSBoolean 、JSString | num 、int 、double 、bool 、String |
JSExportedDartFunction | Function |
JSArray<T extends JSAny?> | List<T extends JSAny?> |
JSPromise<T extends JSAny?> | Future<T extends JSAny?> |
JSUint8Array などの型付き配列 | dart:typed_data からの型付きリスト |
JSBoxedDartObject | 不透明なDart値 |
ExternalDartReference | 不透明なDart値 |
external
宣言とFunction.toJS
の要件
#型安全性と一貫性を確保するために、コンパイラはJSに出入りできる型に要件を課しています。任意のDart値をJSに渡すことは許可されていません。代わりに、コンパイラは、互換性のあるインターオプ型であるExternalDartReference
またはプリミティブを使用する必要があります。これらは許可されます。
@JS()
external void primitives(String a, int b, double c, num d, bool e);
@JS()
external JSArray jsTypes(JSObject _, JSString __);
extension type InteropType(JSObject _) implements JSObject {}
@JS()
external InteropType get interopType;
@JS()
external void externalDartReference(ExternalDartReference _);
一方、これらはエラーを返します。
@JS()
external Function get function;
@JS()
external set list(List _);
これらの要件は、Function.toJS
を使用してDart関数をJSで呼び出し可能にする場合にも存在します。このコールバックに出入りする値は、互換性のあるインターオプ型またはプリミティブである必要があります。
String
などのDartプリミティブを使用する場合、コンパイラで暗黙の変換が行われ、その値をJS値からDart値に変換します。パフォーマンスが重要で、文字列の内容を調べる必要がない場合は、2番目の例のように、変換コストを回避するために代わりにJSString
を使用する方が理にかなっている場合があります。
互換性、型チェック、キャスト
#JS型のランタイム型は、コンパイラによって異なる場合があります。これは、ランタイム型チェックとキャストに影響します。したがって、値がインターオプ型である場合、またはターゲット型がインターオプ型である場合は、ほとんどの場合、is
チェックを避けてください。
void f(JSAny a) {
if (a is String) { … }
}
void f(JSAny a) {
if (a is JSObject) { … }
}
また、Dart型とインターオプ型間のキャストも避けてください。
void f(JSString s) {
s as String;
}
JS値の型チェックを行うには、JS値自体を調べるtypeofEquals
またはinstanceOfString
などのインターオプメンバーを使用します。
void f(JSAny a) {
// Here `a` is verified to be a JS function, so the cast is okay.
if (a.typeofEquals('function')) {
a as JSFunction;
}
}
Dart 3.4以降は、isA
ヘルパー関数を使用して、値がインターオプ型かどうかを確認できます。
void f(JSAny a) {
if (a.isA<JSString>()) {} // `typeofEquals('string')`
if (a.isA<JSArray>()) {} // `instanceOfString('Array')`
if (a.isA<CustomInteropType>()) {} // `instanceOfString('CustomInteropType')`
}
型パラメータに応じて、その型に適切な型チェックに変換されます。
Dartは、JSインターオプ型を使用したランタイムチェックをより簡単に回避できるように、lintを追加する可能性があります。詳細については、issue #4841を参照してください。
null
とundefined
#JSには、null
とundefined
の両方の値があります。これは、null
しかないDartとは対照的です。JS値の使いやすさを向上させるために、インターオプメンバーがJSのnull
またはundefined
のいずれかを返す場合、コンパイラはこれらの値をDartのnull
にマッピングします。したがって、次の例のようなvalue
メンバーは、JSオブジェクト、JS null
、またはundefined
を返すものと解釈できます。
@JS()
external JSObject? get value;
返り値の型がnull許容型として宣言されていなかった場合、返された値がJSのnull
またはundefined
であった場合、プログラムはエラーをスローします。これは健全性を確保するためです。
JSBoxedDartObject
対 ExternalDartReference
#Dart 3.4以降、JSBoxedDartObject
とExternalDartReference
の両方を使用して、DartのObject
への不透明な参照をJavaScript経由で渡すことができます。ただし、JSBoxedDartObject
は不透明な参照をJavaScriptオブジェクトでラップしますが、ExternalDartReference
は参照そのものであり、JS型ではありません。
JS型が必要な場合、またはDart値が別のDartランタイムに渡されないことを確認するための追加のチェックが必要な場合は、JSBoxedDartObject
を使用してください。たとえば、DartオブジェクトをJSArray
に配置する必要がある場合、またはJSAny
を受け入れるAPIに渡す必要がある場合は、JSBoxedDartObject
を使用します。それ以外の場合は、ExternalDartReference
を使用してください。これは高速です。
ExternalDartReference
との間で変換するには、toExternalReference
とtoDartObject
を参照してください。
特に明記されていない限り、このサイトのドキュメントはDart 3.5.3を反映しています。最終更新日:2024年8月4日。 ソースコードを見る または 問題を報告する.