It's still not ready for use. I don't care Enum. But you can not import local files without extensions. You can not define class properties in constructor.
Enums and parameter properties can be enabled with the --experimental-transform-types CLI option.
Not being able to import TypeScript files without including the ts extension is definitely annoying. The rewriteRelativeImportExtensions tsconfig option added in TS 5.7 made it much more bearable though. When you enable that option not only does the TS compiler stop complaining when you specify the '.ts' extension in import statements (just like the allowImportingTsExtensions option has always allowed), but it also rewrites the paths if you compile the files, so that the build artifacts have the correct js extension: https://www.typescriptlang.org/docs/handbook/release-notes/t...
Importing without extensions is not a TypeScript thing at all. Node introduced it at the beginning and then stopped when implementing ESM. Being strict is a feature.
What's true is that they "support TS" but require .ts extensions, which was never even allowed until Node added "TS support". That part is insane.
TS only ever accepted .js and officially rejected support for .ts appearing in imports. Then came Node and strong-armed them into it.
It should be one of the main things bringing you to Rust, because it simplifies a lot of typical concurrency patterns.
When I started out, it felt icky and like some kind of infection that everything eventually had to be async, but that was because I didn't understand how to interact with async code. Using spawn, spawn_blocking, and futures::stream is 90% of my use case, and it makes it easy to set up "barriers" beyond which async doesn't need to spread.
I did a fair bit of Rust (only single-threaded, quite a few years ago) but it sounds like the dependency inversion principle is popping up again.
DIP, async/await, coloured-functions, io-monad. All cases where the business logic should go in one column (abstract/sync/blue/pure), and your machinery should go in the other column (concrete/async/red/io). Your logic will remain unit-testable that way, regardless of how big or small it gets.
Irritated newcomers will complain about not being able to call in the other direction. So what's a language-designer to do? Attract the largest possible user-base by not getting in the user's way - or filter out frustrated users and have fewer but better codebases out there?
Dependency inversion does apply sometimes, but a well-designed library caps async around functions that need it - things that interact with filesystem or network, etc. Those are perfectly testable as-is. Your core business logic is still sync, if you'd like to to be. Async can call sync just fine, and sync can call async, as long as you are willing to admit that you're abstracting away a network call in a unit tests (for some reason).
The typical pattern I enjoy is:
* Sync for the logic
* Async for the job runners b/c I'd like to do other things while it's going.
* Sync or Async as required for the data wrangling (db calls, network, filesystem)
So you have essentially:
1. kick off job, returning a future, by calling an async function.
2. Job is mostly async data wrangling, followed by a sync logic block that's unit tested, followed by an async "save" if required.
3. Either wait for the future, or run the task in the background, or `.await` if you're in an async block.
I'm hand waving away the syntax, but that's the mental model. 99% of code isn't async, and the code that is isn't async for the fun of it.
I know where you're coming from. But for me it's one of the main reasons I use Rust, since it clicked for me after the initial hurdles. Contrary to the average opinion on this, I like the syntax and don't mind so much about function colouring.
Especially when using tokio I feel like my solutions work out pretty well. I also very much appreciate how they create async equivalent functions for pretty much any std function worth using. Maybe this creates a divide, but my concurrent programs feel easy to code and the performance is pretty good.
My only semi-issues are probably stuff like task cancellation, however I attribute that to skill issues on my end, rather than tokio or the way async/await is implemented in Rust.
It has and it's both pretty mature and extensively used. Some users have philosophical reasons against using async/await at all, so I believe that's why the user said that... The other option being the user doesn't like the way it is implemented, compared to other languages.