sdk
sdk copied to clipboard
[JS-interop] Extension for JSBigint
Why JSBigint and Bigint have no extension in js-interop like
/// [JSBigInt] <-> [BigInt]
extension JSBigIntToBigInt on JSBigInt {
external BigInt get toDart;
}
extension BigIntToJSBigInt on BigInt {
external JSBigInt get toJS;
}
I try to create in my project these extensions but i have this error:
Error: Type 'BigInt' is not a valid type in the signature of `dart:js_interop` external APIs or APIs converted via `toJS`. The only valid types are: JS types from `dart:js_interop`, @staticInterop types, void, bool, num, double, int, String, extension types that erases to one of these types, or a type parameter that is bound to a static interop type.
[ ] - 'BigInt' is from 'dart:core'.
[ ] Use one of the valid types instead.
[ ] external BigInt get toDart;
[ ] ^
[ ] lib/main.dart:224:25: Error: JS interop or Native class required for 'external' extension members.
[ ] Try adding a JS interop annotation to the on type class of the extension.
[ ] external JSBigInt get toJS;
[ ] ^
Summary: The user is requesting extensions for JSBigInt and BigInt in js-interop to enable seamless conversion between these types. They are encountering errors related to the use of BigInt in the external extension members, which is not allowed in dart:js_interop.
@redDwarf03 have you tried using js- like js: ^0.6.4 and creating an interop?
import 'package:js/js.dart';
@JS('BigInt')
class JSBigInt {
external JSBigInt(String value);
external JSBigInt add(JSBigInt other);
external JSBigInt multiply(JSBigInt other);
}
class MyBigInt extends JSBigInt {
MyBigInt(String value) : super(value);
MyBigInt addWithDart(MyBigInt other) {
return this.add(other);
}
MyBigInt multiplyWithDart(MyBigInt other) {
return this.multiply(other);
}
}
void main() {
var a = MyBigInt('123456789123456789');
var b = MyBigInt('987654321987654321');
var resultAdd = a.addWithDart(b);
var resultMultiply = a.multiplyWithDart(b);
print('Addition Result: ${resultAdd.toString()}');
print('Multiplication Result: ${resultMultiply.toString()}');
}
@redDwarf03 have you tried using js- like
js: ^0.6.4and creating an interop?import 'package:js/js.dart'; @JS('BigInt') class JSBigInt { external JSBigInt(String value); external JSBigInt add(JSBigInt other); external JSBigInt multiply(JSBigInt other); } class MyBigInt extends JSBigInt { MyBigInt(String value) : super(value); MyBigInt addWithDart(MyBigInt other) { return this.add(other); } MyBigInt multiplyWithDart(MyBigInt other) { return this.multiply(other); } } void main() { var a = MyBigInt('123456789123456789'); var b = MyBigInt('987654321987654321'); var resultAdd = a.addWithDart(b); var resultMultiply = a.multiplyWithDart(b); print('Addition Result: ${resultAdd.toString()}'); print('Multiplication Result: ${resultMultiply.toString()}'); }
No because js is not supported with new JS Interoperability and WASM
https://dart.dev/interop/js-interop
So i don't want to use js. Sorry
I create this dart class based on dart test classes but i think dart core team should expose a method to manipulate Bigint and JSBigInt
import 'dart:js_interop';
@JS()
external JSBigInt bigInt;
@JS('BigInt')
external JSBigInt createBigInt(String value);
extension on JSBigInt {
@JS('toString')
external String toStringExternal();
}
Great request, @redDwarf03.
@kevmoo The same with JSFunction if possible :)
The toDart case is fairly straightforward:
JSBigInt b = ...;
BigInt b2 = BigInt.parse(b.toString()); // toString calls the external toString
The toJS case requires a few more lines but is also straightforward:
@JS('BigInt')
external JSBigInt bigInt(String s);
...
BigInt b = ...;
bigInt(b.toString());
Of course, it'd be useful to add functions that do this for you and have them in dart:js_interop, so we can track this request.
The same with JSFunction if possible :)
Can you elaborate a bit more here? We have Function.toJS and JSExportedDartFunction.toDart today. JSExportedDartFunction is a separate type since not all JSFunctions were converted Dart functions. If you want to call arbitrary JSFunctions, one solution is using JSFunction.callAsFunction.
thx. i will explore your comment on JSFunction
@srujzs about JSBigint and JSArray:
I have an JSArray<JSObject>
2 cases:
1 - I manage conversion directly in dart
@JS()
extension type WriteContractParameters._(JSObject _) implements JSObject {
external WriteContractParameters({
JSArray? args,
});
external JSArray? args;
}
@JS()
external JSBigInt bigInt;
@JS('BigInt')
external JSBigInt createBigInt(String value);
extension on JSBigInt {
@JS('toString')
external String toStringExternal();
}
final writeContractParameters = WriteContractParameters(
args: [
'0x08Bfc8BA9fD137Fb632F79548B150FE0Be493254'.toJS,
createBigInt('498500000000000'),
].toJS,
);
When i debug javascript, i have my bigint correctly managed
args: Array(2)
0: "0x08Bfc8BA9fD137Fb632F79548B150FE0Be493254"
1: 498500000000000n
2 - I don't manage conversion directly in dart
class WriteContractParameters {
WriteContractParameters({
this.args,
});
List<dynamic>? args;
JSWriteContractParameters get toJS => JSWriteContractParameters(
args: args?.jsify() as JSArray<JSObject>?,
);
}
final writeContractParameters = wagmi.WriteContractParameters(
args: [
'0x08Bfc8BA9fD137Fb632F79548B150FE0Be493254',
BigInt.from(498500000000000),
],
);
When i debug javascript, i have my bigint NOT correctly managed
args:
Array(2)
0: "0x08Bfc8BA9fD137Fb632F79548B150FE0Be493254"
1: core._BigIntImpl.__ {Symbol(_used): 4, Symbol(_digits): Uint16Array(4), Symbol(_isNegative): false}
length: 2
Symbol(dartx.arrayRti): (...)
Symbol(dartx.first): (...)
Symbol(dartx.hashCode): (...)
Symbol(dartx.isEmpty): (...)
Symbol(dartx.isNotEmpty): (...)
Symbol(dartx.iterator): (...)
Symbol(dartx.last): (...)
Symbol(dartx.length): (...)
Symbol(dartx.reversed): (...)
Symbol(dartx.runtimeType): (...)
Symbol(dartx.single): (...)
[[Prototype]]: Array(0)
So i would like to fix my case 2
Yeah, we currently don't treat BigInts specially in jsify and treat them as other Dart members, so it'll be a bit more of a manual process. There's a blanket bug here: https://github.com/dart-lang/sdk/issues/55222 to be clear about what jsify/dartify can and can't do (right now we only technically support whatever's in the doc comment) as well as make it consistent. One of the options there is allow users to expose the low-level conversion methods they need so they can write their own variants that convert types as they need.
@srujzs i tried something like that but the add method seems to add nothing...
JSArray<JSObject>? _convertArgs(List<dynamic>? args) {
if (args == null) {
return null;
}
final jsArgs = JSArray<JSObject>();
for (final arg in args) {
if (arg is String) {
jsArgs.add(arg.toJS);
} else if (arg is int) {
jsArgs.add(arg.toJS);
} else if (arg is bool) {
jsArgs.add(arg.toJS);
}
}
return jsArgs;
}
@srujzs i tried something like that but the add method seems to add nothing...
JSArray<JSObject>? _convertArgs(List<dynamic>? args) { if (args == null) { return null; } final jsArgs = JSArray<JSObject>(); for (final arg in args) { if (arg is String) { jsArgs.add(arg.toJS); } else if (arg is int) { jsArgs.add(arg.toJS); } else if (arg is bool) { jsArgs.add(arg.toJS); } } return jsArgs; }
@srujzs is it possible to add BigInt in the condition https://github.com/dart-lang/sdk/blob/ee0b971dbd6ff51d8ec740294fb0a2730df6bb2b/sdk/lib/_internal/wasm/lib/js_util_patch.dart#L32
i tried something like that but the add method seems to add nothing...
There's no add method on a JSArray. You may want push e.g.
extension JSArrayExtension<T extends JSAny?> on JSArray<T> {
external void push(T _);
}
Besides that, the approach seems fine, but it is a bit of reinventing jsify alas.
is it possible to add BigInt in the condition
One of the things we want to do for jsify/dartify is expose it in such a way that users can define their own conversions if needed. Maybe a callback would be useful here for types that aren't supported by default, but it'd be nice to customize jsify/dartify as needed at any rate.