dartdart-js-interopdart-dev-compiler

Using Dart JS interop with ES6 classes


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 { ... }