Haxe is truly fascinating and Neko is a great engine as far as I could test. But the language suffers from global scale adoption, not due for the quality but due to the lack of big names representing, I feel.
Fyi, at this point the Neko VM has more or less been replaced by its spiritual successor HashLink (used by games such as Northgard and Dead Cells). It achieves better performance by being a strictly typed VM. It also has better tooling (breakpoint debugging in VSCode, profiling).
I don't think ActionScript <> JavaScript is as important here as everything else about Haxe (full / safer static types, speed, multi-backend, pattern matching, etc.) and Typescript (gradual typing to support idiomatic JS code at the cost of being unsound by design).
If you applied Typescript's philosophy and design to AS instead of JS, you'd get something much closer to Typescript than to Haxe, is what I'm saying.
I've been using both professionally for a number of years, I prefer to use haxe when I can. Strengths of both need to be considered, to give an overview of why I prefer haxe:
TypeScript's main strength is its proximity and integration with js; it didn't seek to reimagine js, but build typing on top of it.
Haxe instead builds strictly typed ECMA language from a clean slate:
- Language features are simpler because it doesn't have to contend with legacy JS (importing a module is just `import X`, strings are always multi-line, `this` means current class etc)
- It's a hybrid functional language, so you can write haxe like you'd write TypeScript, but everything is also an expression, so you can use functional patterns:
// the switch statement is an expression and so evaluates to a value
var message = switch httpCode {
case 404: 'Not Found ($httpCode)';
case 200: 'Success ($httpCode);
case code if (code >= 500 && code < 600): 'Server Error';
default: 'Http Error $httpCode';
}
// even the for-loop is an expression
var array = [for (i in 0...10) i]; // array of Ints from 0 to 9
- Compile-time code execution removes the need for build tools – you can mark functions to execute at compile time, so you can do all your asset processing / DSLs / build-tool-fun as part of the regular compilation. (This is perhaps the biggest win over the traditional web stack for me; I _hate_ web build tools)
- Target other server backends like PHP or Python, which is handy if you're writing a web service and want to use libs from other ecosystems
- The compiler is many times faster
On downsides when compared with TypeScript:
- Is it can be harder to use js-centric libraries like Vue, which make use of JavaScript's `this` behavior in their API design (in contrast to libraries like three.js which are more traditional)
- Haxe does not consume .d.ts files directly but they can be converted to haxe files with the dts2hx tool. This works for many libraries, but isn't yet perfect. For complex libraries like React, it's best to use a hand written haxe-react project (e.g. https://github.com/kLabz/haxe-react)
- Haxe's type system is more strict than TypeScript's, in TypeScript you can perform complex type operations but to achieve the same in haxe you need to use compile-time macros. This is primarily an issue when using existing TypeScript libs which make use of advanced type expressions (which if too complex may become 'any' when translated to haxe)