Type inference (completion hint) woes

I’m trying to convert a nodejs Express server implementation from TS to Haxe, so I started playing with haxe-js-kit, which seems to be the only complete set of Haxe externs for Express.js. I then noticed Haxe wouldn’t infer the types for the Request and Response params for the use() callback. Code example follows:

package server;

import js.npm.Express;

class Main {
  static var app = new Express();

  public static function main() {
    app.use('/foo', (req, res) -> {}); // <-- HERE
    app.listen(Config.SERVER_PORT);
  }
}

The req and res parameters to the anonymous callback function are shown as Unknown<0> when I $type() them or hover over them in vshaxe, as you may see in this screenshot: Loading | Collabshot - annotate screenshots online with your friends.

The problem, it seems, is related to the way the parameters for the use function are implemented, basically a Rest typed as a abstracted called AbstractMiddleware that can convert to several other types depending on the context: haxe-js-kit/Middleware.hx at develop · clemos/haxe-js-kit · GitHub.

After some discussion on the #haxe Gitter channel, we didn’t come to a conclusion on why it wasn’t working, but @Gama11 was kind enough lend some of his time and came up with a solution that relies on EitherType.

typedef AbstractMiddleware = EitherType<MiddlewareErrorHandler, EitherType<MiddlewareResponder, EitherType<MiddlewareHandler, Middleware>>>;

This seems to solve and instruct Haxe to correctly infer the types for the aforementioned params, as you may see here:

Even though the EitherType solution seems to work, I’m intrigued on why the original solution based on an Abstract doesn’t.

Does anyone know what are the rules for resolving the right type for that abstract based off the expression passed as the argument of use()? Why would Haxe not infer the types in the example I showed at the beginning of this post?

UPDATE: Actually I think the EitherType solution doesn’t work in that context either. I finally had some time to play with it and I couldn’t reproduce the results from @Gama11.

I even tried adding the type annotation to the first or the last params of the callback function, but Haxe still shows the other one as <Unknown<0>>. So I don’t really know how @Gama11 made it to work here:

I guess it’s unreasonable to expect Haxe to infer the types from just param names/order, considering the names are not even a type hint of any kind. It needs more hints. So I think the way to go here is to just annotate all params in the callback function with the types I expect in order for Haxe to resolve the right typedef from the Abstract or EitherType, right?

I haven’t looked at the TS type definition for the same method, but it’d be interesting to compare how TS does the same resolution and how the definition compares to the js-kit approach, for the sake of learning. I’ll get to that soon and post my findings here.

Ok, here’s the last episode of the soap opera: I just found out that what I thought didn’t work, seems to work (yay!), but the problem is the inconsistent way Haxe shows the type completion hint (or vshaxe or both, I don’t know if this is a Haxe or vshaxe issue). More info on Gitter: :point_up: May 22, 2019 1:44 AM. Possibly a bug in the completion server?

This issue has been reported at the Haxe repo, here.