Using Dart JS interop with ES6 classes

Issue

JavaSscript:

class MyClass {

    constructor() {
        console.log("MyClass instance created");
        this.answer = 42;
    }
}

let example = new MyClass();
console.log(example.answer);

Dart:

@JS()
library interop_test;

import 'package:js/js.dart';

@JS()
class MyClass {
  external int get answer;
  external set answer(int value);
}

Creating an instance of the the interop class MyClass as

MyClass myClass = MyClass();

results in:

EXCEPTION: TypeError: dart.global.MyClass is not a constructor

I’ve also tried to add a external MyClass(); and external factory MyClass(); to the @JS() annotated class, but got the same message. If I add @anonymous annotation to the interop class, the exception goes away, but I can’t access instance members. (But I don’t see why this would need the anonymous annotation)

I’m using dart 2.0.0, angular 5.0.0, js 0.6.1+1 and dartdevc through webdev.

Solution

Normally JS interop would rely on function hoisting to ensure that an old-style JS class was in scope. ES6 classes however aren’t hoisted and aren’t available where Dart expects them to be. There are several different ways you can make the class available to Dart:

Placing the class object on the window

This places the class in the same scope that a function definition would be hoisted to. In JavaScript:

class MyClass { ... }

window.MyClass = MyClass;

Creating a module object

You can also place the class in a sort of pseudo module or namespace. In JavaScript:

class MyClass { ... }
var myModule = { MyClass: MyClass };

Which is then accessible at myModule.myClass in Dart:

@JS('myModule.myClass')
class MyClass { ... }

Answered By – Jonah Williams

Answer Checked By – David Goodson (FlutterFixes Volunteer)

Leave a Reply

Your email address will not be published. Required fields are marked *