js.Promise to wrap a javascript library method

In order to implement the media autoplay changes in Chrome browser I’m having to engage with Javascript Promises, but I’m unsure how to properly use js.Promise.

Here is the javascript sample from the link above:

var promise = document.querySelector(‘video’).play();

if (promise !== undefined) {
promise.then(_ => {
// Autoplay started!
}).catch(error => {
// Autoplay was prevented.
// Show a “Play” button so that user can start playback.
});
}

firstly, in haxe mediaElement.play() returns Void so I tried to cast this to Promise, but that gave a “Invalid number of type parameters for js.Promise”, and I’ve no idea what the type returned by javascript’s promise is.
Typing to Dynamic bypassed the compiler error, but is not ideal.

secondly, haxe has no ‘undefined’ type, so I’ve optimistically changed this to a null check.

thirdly, I’ve had to change .catch to catchError as ‘catch’ is a keyword, but because promise is Dynamic rather than a proper Promise, the compiler does not convert catchError back to catch in the javascript output. So I fix that issue up post-compile and the code runs correctly.

var promise:Dynamic = cast mediaElement.play();
if (promise != null) {
promise.then(function() {
// Autoplay started!
}).catchError(function() {
// Autoplay was prevented.
trace(“AUDIO PLAY ERROR:” );
});
}

So what should the proper syntax be to ensure that the javascript Promise is mapped correctly to the haxe Promise?
Thanks, Jake

You can’t really use a Promise as Dynamic, that would break the renaming of catchError to catch.

js.Promise has a type parameter corresponding to the type of what this promise resolves to. In this case, it seems like this type is Void, which is not perfectly handled in haxe.

You can do

var promise:js.Promise<Void> = cast mediaElement.play();

or

var promise:js.Promise<Noise> = cast mediaElement.play();

if you are using a library which defines an empty enum as Noise (or do it yourself)

But then, even if your promise as no data, you need to catch the first argument:

promise.then(function(_) {

As for why mediaElement.play() returns Void, it’s because specs have changed and haxe is not up to date:
https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/play

Note that the WHATWG and W3C versions of the specification differ (as of April 20, 2016) as to whether or not this method returns a Promise or nothing at all, respectively.

Thank you for your reply kLabz,

var promise:js.Promise = cast mediaElement.play();

I did try this, but got the compiler error:
lines 456-458 : Arguments and variables of type Void are not allowed
where lines 456 - 458 are

function(_) {
// Autoplay started!
}).then(null, function(error) {

so it seems something is still wrong.

However, I’ve gotten round the catchError problem by following this hint
My code is compiling and working as expected, albeit not typesafe due to the Dynamic :
var promise:Dynamic = cast mediaElement.play();
if (promise != null) {
promise.then(
function(_) {
// Autoplay started!
}).then(null, function(error) { // replaces catchError
// Autoplay was prevented.
trace(“AUDIO PLAY ERROR:” + error.toString());
}
);
}

Seems like cast won’t work actually, because of the Void return.

I don’t recognize your error, what version of haxe are you using?

Haxe 3.2 I’m afraid to say. Jake