Tsrs: A Port of TypeScript to Rust
Posted by hnisjafx40 2 days ago
Comments
Comment by DanRosenwasser 1 day ago
We think the wasm and oxlint integration makes a lot of sense for Cloudflare's needs, so this investment makes sense. At the same time, we'll be working hard and collaborating to make the official TypeScript toolset faster and even more efficient.
Congrats to the tsrs team on making this official. We're excited and we look forward to continuing on collaboration!
Comment by samuelstros 1 day ago
No matter how many optimizations can be ported from tsrs to ts-go, Rust will be more efficient and enable the WASM use case.
The premise of porting the compiler from TS to GO was ease of migration due to Go's garbage collector. That doesn't hold anymore? AI doesn't care how hard or easy a migration is if a test suite exists.
Comment by magicalist 1 day ago
Sure, but that only matters if migration is going to be the last thing anyone does on a project. Unless you think typescript 7.1 ought to be enough for anybody, it also matters what the typescript team wants to write/read/reason in.
Comment by collabs 1 day ago
Comment by platinumrad 1 day ago
Comment by written-beyond 1 day ago
Comment by simplesocieties 1 day ago
Comment by fmbb 1 day ago
Comment by hdjdnxjzhzhs 1 day ago
Comment by z3t4 1 day ago
Comment by Too 1 day ago
Comment by jon-wood 1 day ago
Comment by cpursley 1 day ago
Native UI with Crux backend. Best of both worlds.
Comment by cute_boi 1 day ago
Comment by afdbcreid 1 day ago
Comment by awesome_dude 1 day ago
It still, like every other language/tool we have that shares state between threads, has race conditions, for example.
Comment by RussianCow 1 day ago
Comment by vovavili 1 day ago
Comment by Kamq 1 day ago
As an example, let's say you have two functions A and B. A only works properly if B has never ran for some reason. Let's say they both accept a reference to a value C, and B changes C's value somehow. Because this is rust, we can't have data races, so we wrap it in an ArcMutex or what have you. That doesn't impact the ordering of A and B at all.
If we spawn threads that execute A and B at the same time, it's up to the scheduler if A functions properly.
Comment by awesome_dude 8 hours ago
And that is my core complaint - data races are well-understood and preventable now, whether statically via Rust's borrow checker (or pure immutability in functional languages) or dynamically with tools like Go's -race detector.
Logic races remain an application-level problem regardless of language design.
Comment by rrvsh 1 day ago
Comment by dnautics 1 day ago
Maybe I spend too much time on tech internet...
Comment by awesome_dude 1 day ago
Please copy and paste from my post where that's being asserted
> Its touted purely as a _memory_ safe language
Which is different from what was said... how?
> To claim otherwise is absurd and very telling of the writer's biases
To pretend that those claims were made is what's actually telling of biases.
Comment by afdbcreid 1 day ago
Because memory safety isn't just about data races. In fact data races are far from Rust's most innovative or important feature. They are a side-effect, the designers had a nice system and saw it can also prevent data-races, so they said "sure, why not".
Comment by solyin 1 day ago
Comment by wavemode 1 day ago
Your question boils down to "why would humans maintain something?" which could have a variety of answers depending on context.
Comment by pjmlp 1 day ago
Comment by greenavocado 1 day ago
Comment by stephbook 1 day ago
"Just" publish the language specs and be done.
Comment by Rapzid 1 day ago
I don't think a spec would facilitate them at such a low effort level and cost.
Comment by mrgoldenbrown 1 day ago
Comment by greenavocado 1 day ago
Because at the end of the day, someone has to actually care and put in effort, even if the thing is machine generated, because it can go off the rails.
Comment by lifeisloving 1 day ago
Comment by melodyogonna 1 day ago
Comment by zarzavat 1 day ago
A Rust implementation will have the fastest compilation speeds, memory safety, can easily be compiled to WASM, or compiled to a native node module.
A TypeScript implementation provides the most convenient way for TypeScript code to use the typescript package as a library. Pure JS, no native code or WASM dependencies. No FFI tax, can be jitted.
Go was always a compromise to make a port easier for humans. Go's GC makes it easier to keep the general code structure from the TS implementation. However that GC is also a liability, you sacrifice speed and embeddability.
Personally I'd prefer they went back to TypeScript for the reference implementation, and used Rust for the performance implementation. Go doesn't bring anything to the table anymore.
Comment by afdbcreid 1 day ago
Incorrect. I can maybe agree that those are the only perfect languages to implement tsc in them (if there is such thing). But in the real world, "perfect" does not actually mean "it's a good idea". Go made the most sense to port to (especially before agents), more than Rust (although C# could also be a good idea IMO).
Comment by ameliaquining 1 day ago
Comment by WorldMaker 1 day ago
I also still think C# would have been a better long term option for maintainability, but I'm not on the Typescript team and didn't get a vote, and I can understand their methodology even if I don't agree with it.
Comment by anonymous908213 11 hours ago
It has no such thing. C# has top-level statements in one file per project, which omit the usual entrypoint Main boilerplate, but that's the extent of it.
Comment by fallingbananna 1 day ago
I assume that most of the speedup in ts-rs does not simply stem from using a language without garbage collection, but actually from doing smart optimizations that can be done in any langauge.
Similar to how uv in the Python world explained that their implementation being in Rust has very little to do with the most impactful speedups they did.
Comment by throw567643u8 1 day ago
Comment by jbellis 1 day ago
Comment by pier25 1 day ago
Sure the Rust version is faster but the difference is probably only noticeable in the top 1% largest projects.
Comment by theappsecguy 1 day ago
Comment by alain_gilbert 1 day ago
Comment by pier25 1 day ago
Comment by tialaramex 1 day ago
On foot I cross the little residential street where I live, walk to the corner, cross the busier road using a Zebra that was installed by thoughtful "pedestrian first" local government, then walk to the next corner where the main entrance to the supermarket is.
In the F1 car lets assume somebody already pre-warmed it and so it's ready to go (F1 cars do not "just work" like your family car because that's not required in the F1 rules) I walk to the car park and get in, I need to accelerate quite hard to get the slippery F1 car up the steep drive, but then brake hard to stop and have somebody else check both ways since an F1 car isn't equipped for this in a side street. Now I pull out, takes no time to reach that street where pedestrian me crossed but I can't use that route in a car, so, go through another residential area, turn onto an old main road, turn again, to a roundabout, go into the underground carpark of the supermarket. Once I've parked I'm about as close to the front door as if I were walking from the Zebra. Huh.
Comment by suriyaG 1 day ago
but tsrs and tsgo are not a similar comparison. they cost the same (you download a binary and run it) and are functionally identical. in that case why would you not use the faster & better one?
the question should be, do you always want your groceries 50% faster ?
Comment by wiseowise 1 day ago
Comment by riknos314 1 day ago
The question isn't really if the speed is bad, it's what tradeoffs you need to make to realize it. The F1 car has a very narrow operating condition and so can make tradeoffs that are completely unreasonable for vehicles that need to do other things.
From what cloudflare is claiming, Tsrs gives me more speed without tradeoffs I care about, so why not have the free speed?
Comment by baq 1 day ago
Comment by solyin 1 day ago
Comment by AnnikaL 1 day ago
Comment by sophacles 1 day ago
An F1 car goes faster but also uses more fuel to do so.
Any one tool being a bit faster doesn't make my batter last noticeably longer, but defaulting to using the efficient tooling gets me results I can see.
Comment by alain_gilbert 1 day ago
Comment by pier25 1 day ago
Obviously a shovel is quite an improvement for home gardeners but big constructions need a completely different tool.
For +99% of TS projects going from eg 10ms to 1ms is not going to make any difference even though it's a 10x improvement. In part because most monitors refresh at 60hz (16ms per frame) but even with +120hz monitors this is not going to have an impact on any workflow. Even for CI network latency is going to be a much bigger factor than improving TS compilation beyond the performance that TSGO already provides.
Comment by eyelidlessness 1 day ago
That’s already meaningful for at least a couple of companies I’ve seen investing in these ports. It might be niche for individual dev workflows now, but as those evolve it could become less niche (albeit probably still less uniform).
Comment by pier25 1 day ago
For sure but those high volume use cases are extremely rare.
Comment by com2kid 1 day ago
But in any given year I maybe plant a dozen new plants tops. 6 tomato plants and half a dozen other random things.
Comment by seanw444 1 day ago
Comment by wiseowise 1 day ago
Comment by Tadpole9181 1 day ago
"Would you rather have worse software for literally no benefit?"
We should aim to make software as performant, bug free, feature-complete, and maintainable as is cost effective. It's asinine to argue that software shouldn't be fast, not because of some trade off, but just because someone doesn't need it to be fast for small tasks.
Which, mind you, isn't even the case here. Thousands of businesses use typescript for millions of lines of code. Performance gains can mean tens of thousands of dollars in compute or hardware or time; tons of carbon saved from being emitted.
Comment by afiori 1 day ago
Comment by Tadpole9181 1 day ago
Comment by afiori 1 day ago
the analogy is not between each specific consequence/cost, it is relative to "single axis optimization" not being a solid strategy
Comment by norman784 1 day ago
Comment by skybrian 1 day ago
Comment by madeofpalk 1 day ago
Comment by samuelstros 1 day ago
Comment by lifeisloving 1 day ago
Its a great way to divide and kill the popularity of your project. I made sure bun is no longer used in my devices or projects that depend on it for example, I'm not alone in this.
Comment by egonschiele 1 day ago
Comment by lifeisloving 1 day ago
This is probably the most harmful tech ever created simply because how many people trick themselves into thinking they're smarter while actually becoming much dumber. We're actually cooked.
Comment by lemagedurage 1 day ago
Could you elaborate on what type of optimizations were added to TS 7.1? As in, were they more algorithmic or related to memory management?
Comment by DanRosenwasser 1 day ago
Comment by zyf 1 day ago
Comment by zylepe 1 day ago
Comment by satvikpendem 1 day ago
Comment by afdbcreid 1 day ago
Essentially, they fake a GC via never-freed arenas for long-living objects. It's interesting that Rust can do that (hopefully soundly)!
Comment by dabinat 1 day ago
Another advantage human ports have is the opportunity to reconsider earlier architectural decisions and change them, instead of just enshrining them in the new language.
Comment by wewxjfq 1 day ago
Comment by rk06 1 day ago
Only practical option is to do low level rewrite (otpion 1) and then rewrite module by module into better approaches.
Comment by zamalek 1 day ago
>Create with P::new(value). p.get() returns &'static T. [...] unless an explicit recycling site proves them dead
It's unsound, the LLM/human is doing the proving. They've hidden unsafe in an abstraction without removing the unsafeness. Using the arena allocator's lifetime would have been safe and easy (bumpalo recommends this AFAIK).
I'm guessing a sycophantic LLM either found or praised this load-bearing seam.
Never deallocating would have been sound (missile memory management: https://devblogs.microsoft.com/oldnewthing/20180228-00/?p=98... ).
Comment by tengbretson 1 day ago
Calling this a breakthrough in memory management is an understatement. Call up the Turing Award committee. We just discovered a solution to the halting problem! Turns out that for certain applications the answer is unequivocally "yes"
Comment by solyin 1 day ago
Comment by afdbcreid 1 day ago
Comment by lioeters 1 day ago
Zing!
Comment by jcmontx 1 day ago
Comment by panzi 1 day ago
A long time ago I read an article about someone speeding up a C++ compiler that is itself written in C++ (was it g++? maybe clang?). They simply patched out delete so it did nothing. The compiler used marginally more memory but ran much faster, since releasing all the small objects one by one is just useless work at the end of the compilation.
A GCed language has a similar behavior and could therefore be fast in that case. It just builds up all the objects and then when the program exists it doesn't have to GC them all, it just throws away the whole process memory. So I can imagine one could "optimize" a compiler written in a GCed language by deactivating the GC.
Comment by jamesfinlayson 1 day ago
Comment by sheepscreek 1 day ago
It wasn’t “let’s build a faster Rust based Typescript compiler” at all. That was a nice side-effect.
They needed a Typescript compiler that can run on their WASM only sandbox. So the only existing option was to export tsc Go to WASM, but that comes with the full Go runtime.
And to avoid that cost, they experimented with a Rust compiler and turns out it’s even faster than the reference tsc/Go implementation.
Comment by nitsky 1 day ago
Comment by h14h 19 hours ago
Built this little vibe-coding app as an experiment/cost exploration: https://glare.run
It's awesome how cheaply you can run an entire agentic coding loop (including compilation & live reload) in their v8 isolate sandbox.
Comment by simplesocieties 1 day ago
Then why are the performance graphs the headliner topic in the article? The WASM sandbox is barely a footnote.
Comment by sheepscreek 1 day ago
If you’ve got it, flaunt it?
> The WASM sandbox is barely a footnote.
This one is a real head scratcher. The sandbox was clearly what set them on this path.
Maybe they believe the performance gains are worthy of being discussed by themselves?
Comment by xboxnolifes 1 day ago
Comment by sara_kumodeck 1 day ago
Comment by egonschiele 1 day ago
> However, frontier AI models can now do large-scale ports almost independently in a matter of days
> I wrote zero code. Not "barely any". Zero
So we are going to move from a carefully handwritten port to an entirely AI-generated port. I know this is the way the industry is headed, I use coding agents a ton. But I still review their output because they often don't make sound architectural decisions. Maybe this is a sign that my way of working is going away. I'm not sure how to justify that kind of time spent when someone can do the same thing in a matter of days with barely any effort.
I am working on my own language now, I've spent most of this year on it. The idea that someone could just replace it in a matter of days is wild. Wonder how the TS team at Microsoft feels about this.
Comment by TheSamFischer 1 day ago
They didn’t design a language that millions of human engineers enjoy (?, lol) using. They took an existing codebase and ported it. Yes, the porting part is easier now but only because another project and spec exist.
Comment by FuckButtons 1 day ago
Comment by TheSamFischer 1 day ago
Comment by pas 1 day ago
Comment by egonschiele 1 day ago
Comment by onlyrealcuzzo 1 day ago
You do have to be worried that it's possibly installing trojan horses on your computer while compiling code, or any other number of unwanted side effects.
But you can and should be able to have integration testing in place to know that a compiler - at a minimum - actually works.
Comment by egonschiele 1 day ago
Comment by filopedraz 1 day ago
Comment by spiderice 1 day ago
Comment by 0x696C6961 1 day ago
Comment by lioeters 1 day ago
Comment by vips7L 1 day ago
Comment by simplesocieties 1 day ago
Comment by oersted 1 day ago
Comment by simplesocieties 1 day ago
> We cannot ignore individual benefits in contributing, but that is not everything.
Individual benefits are the very foundation of most collaborative efforts. Pharmaceutical companies get payouts via patents for researching life-saving medicine. Even with money taken out of the equation, many academics slave for years over their research in hope of recognition either via Tenure or Nobel Prize. Ignoring the fact that people want credit for their work is dangerous and irresponsible.
Forking projects that are near-complete or have already undergone major refactors just to snipe them last-minute with vibe coded efforts is going to kill collaboration. I'm never building another project in the open again because that is precisely what I'm aiming to avoid.
Comment by vips7L 1 day ago
Comment by jrop 1 day ago
Comment by gzapp 1 day ago
Comment by gzapp 1 day ago
I didn't push performance in a way that would cause big deviations from the Golang project's algorithms and data structures; similar to how the TS team didn't want to deviate too far from the JavaScript source till now. Aggressive unmanaged arenas and object pooling was the direction I would have pursued..
The GC in DotNet is a source of major frustration for a tool like this. Without tuning lots of gen 0/1 work occurs to determine if objects should be promoted. The tuning is still not an ideal solution IMHO. Fully unmanaged arenas and aggressive object pooling could help here, but an alternative GC may be part of an ideal, comprehensive solution.. I have have a play with ZeroGC.
There is a warning on the repo that it's not maintained, but I've been curious about the process of updating it to sync "upstream" changes. And it sounds like the TypeScript team are going to start incorporating some of the performance techniques identified in the Rust port in the 7.1 release so... I'll probably at least sync it to up to 7.1 and keep it as an active experiment and case study on LLM porting and DotNet AOT performance.
It's just good fun.
Comment by WorldMaker 1 day ago
Comment by gzapp 1 day ago
The benefit of those enhancements being wrapped into the reference implementation is it's "easier" for humans and LLMs to reconcile and keep things in sync.
Comment by Leynos 1 day ago
Comment by alexanderson 1 day ago
Comment by Rapzid 1 day ago
Comment by preommr 1 day ago
youtuber vibe codes a transpiler says they're not going to bother maintaining it - but big company like cloudflare takes it seriously enough to absorbe into their own official services.
What is happening?
What is even software dev anymore?
What didnt the labs or cloudflare do this themselves, I mean they did, but then if it's all vibe coded, why do they need someone else's vibe coded stuff?
How is any of this serious?
Comment by x-complexity 1 day ago
Because even if vibecoded, the initial work has already been done, and it would be absolutely foolish to outright dismiss it just because it doesn't meet puritanical standards.
> How is any of this serious?
It isn't & shouldn't be. The upfront demand for "serious" is what kills public projects in the first place, where they all come from an experimentation perspective.
There is no public project out there that (from its first commit) was fully serious: Each & every one of them were offshoots & experiments, testing to see if the thing was possible in the first place.
Comment by Leynos 1 day ago
Comment by AbuAssar 1 day ago
Microsoft should seriously consider porting typescript to rust at this point
Comment by aleksandrm 1 day ago
Comment by satvikpendem 1 day ago
Comment by nish__ 1 day ago
Comment by satvikpendem 1 day ago
Comment by rk06 1 day ago
Comment by ndr 1 day ago
IIRC at the time of the port to go they wanted fast test and compile time, of course it's a different era now.
Comment by lemagedurage 1 day ago
Comment by Rapzid 1 day ago
This can type check and compile VSCode in less than a second?
Comment by lemagedurage 1 day ago
Comment by rs_rs_rs_rs_rs 1 day ago
Comment by magicalist 1 day ago
Comment by Rapzid 1 day ago
Comment by tgv 1 day ago
Comment by ruther4d 1 day ago
Comment by msdz 1 day ago
Why not vibecode a Go -> WASM cross-compiler, then?
Comment by AbuAssar 1 day ago
Comment by Lvl999Noob 1 day ago
Comment by WorldMaker 1 day ago
Comment by zamalek 1 day ago
Comment by kg 1 day ago
I think it made sense for them to compromise, at least on the initial version of Wasm GC, to get it out the door. I say this as someone who wants the features that got left out, like interior references :)
Comment by Tadpole9181 1 day ago
Comment by msdz 1 day ago
Comment by jerf 1 day ago
Since a typescript compiler isn't "a small amount of code", you'd have to see specific numbers on the final WASM assembly size to know how relevant that is. I'd expect well-written Rust code to beat well-written Go code on final assembly size by some amount, which may or may not be relevant to any particular use case (since in a lot of cases one "couple dozen megabytes" is much the same as another when it really gets down to it, it's not like Go is going to be emitting gigabytes to Rust's hundreds of kilobytes or something). However I can't judge what AI-written Rust code versus well-written Go code would come out as. AI is not terribly good at being concise (he said, while writing this post between prompts fighting with an AI to make a PR much more concise than it currently is).
Comment by ZiiS 1 day ago
Comment by Tadpole9181 1 day ago
2. They're doing this for workers, so with a systems-level language, there's a much higher potential for CPU and memory savings (an order of magnitude on this first pass, apparently). Driving their compute costs down is very revenue-efficient at this scale.
Comment by tgv 1 day ago
Comment by Tadpole9181 1 day ago
> Just a few weeks ago we announced supporting native Rust in Workers with the new Emscripten target for wasm-bindgen. When you run entire software build and deployment systems in tight loops on Workers, the benefits of a small memory footprint pay off quickly.
Comment by TheMrZZ 1 day ago
Also, faster feedback loop is crucial for AIs, so I guess this makes sense.
Comment by pjmlp 1 day ago
Don't rewrite into Rust, Go, Java, .NET, Zig, Odin, whatever.
Start with them directly.
Comment by eterm 1 day ago
Comment by pier25 1 day ago
It's not. Even the JS compiler is still fast enough for many projects given the single core improvements in hardware (eg Apple Silicon).
Comment by mohammedalfarra 1 day ago
Comment by kidby 1 day ago
Comment by mohsen1 1 day ago
Congrats to the team on getting this out
Comment by weinzierl 1 day ago
If the improvements were discovered by porting to a different language they very much come down to language choice (even if they can be implemented in the source language of the port).
The "fearless ..." mottos of Rust are not hyperbole but a serious point. They allow you (and the LLM) be brave with optimizations.
Comment by norman784 1 day ago
Comment by austin-cheney 1 day ago
Both Bun and Node.js will execute Typescript directly without a compile step. If you are able to write your own front-end bundler then the front-end code also gets the same type stripping from either Bun or Node.js. Since both Bun and Node.js start up my large applications about twice as fast as the Typescript compiler executes I don't see any reason to bother.
Comment by zarzavat 1 day ago
Comment by throw567643u8 1 day ago
Comment by jscheel 1 day ago
Comment by wannabe44 1 day ago
Comment by hollowturtle 1 day ago
Comment by sethaurus 1 day ago
Comment by brazukadev 1 day ago
Comment by ninalanyon 1 day ago
Comment by yabirgb 1 day ago
Comment by LudwigNagasena 1 day ago
Comment by frangonf 1 day ago
Comment by ComputerGuru 1 day ago
Comment by panzi 1 day ago
Comment by dalmo3 19 hours ago
Comment by fg137 1 day ago
Never heard the name again after the initial hype.
Comment by sakesun 1 day ago
Comment by egeozcan 1 day ago
Comment by nsm 1 day ago
You almost definitely don't need to immediately plan to switch.
Comment by cryptonym 1 day ago
True. Looks like main use-case is AI Agent Sandboxing
Comment by ameliaquining 1 day ago
Comment by esafak 1 day ago
Comment by tonyhart7 1 day ago
Comment by AntonyGarand 1 day ago
Comment by francislavoie 1 day ago
Comment by sinameraji 1 day ago
this is great for getting work done faster but also much better if you want to run concurrent agents/worktrees at scale”. https://x.com/feedthejim/status/2112584843368570921?s=46
then i went and tried this on my own open source harness. type checking went from 10 seconds to under half a second and uses a quarter of the memory. madness
Comment by jdw64 1 day ago
Comment by zeroq 1 day ago
Comment by satvikpendem 1 day ago
Comment by jdw64 1 day ago
Comment by wyc610721 1 day ago
Comment by btucker 1 day ago
Comment by souvlakee 1 day ago
Comment by tonetheman 1 day ago
Comment by g0ld3nrati0 1 day ago
Comment by preg_match 1 day ago
Comment by cpursley 1 day ago
Comment by bakugo 1 day ago
Comment by cpursley 1 day ago
Comment by vips7L 23 hours ago
Comment by sashank_1509 1 day ago
Comment by hollowturtle 1 day ago
Ehm no, added type safety, and dealing with a type checker it's exactly what agents need.
> if no human is coding
Nope outside the bubble there are many still hand coding(me too)
> I guess it will be soon that typescript won’t matter anymore since agents will be writing code is Rust
Oh hold on a second isn't Rust the same as Typescript "adding human readability"?! Why not trashing Rust and just have LLMs output WASM directly? XD Wasm which is basically useless outside the browser or some microvms on the edge, and in the browser you don't even have an interface for directly rendering anything and still have to deal with the dom
You either are highly non technical, very junior or I just don't know
Comment by fg137 1 day ago
You need a quick reality check.
Comment by retropragma 1 day ago
Comment by _sinelaw_ 1 day ago
With HM-style type inference, row-polymorphism, sum types, type classes for overloading + operations, recursive types for object methods, and type annotations for edge cases.
I've been working on this since before TypeScript existed. Latest incarnation: https://github.com/sinelaw/inty
Demo: https://sinelaw.github.io/inty/ (you may need to reload once)
Comment by madeofpalk 1 day ago
that same type system exists in the javascript language (jsdoc). doing those type checks is the 'slow' part that makes go / rust appealing. not just stripping types to emit js.
Comment by brazukadev 1 day ago
Comment by _sinelaw_ 1 day ago
inty infers more - including generics (parametric polymorphism), while tsc is more of a simpler local inference.
inty is more strict - it accepts less programs than tsc would. This is mostly on purpose (to our benefit) as some of those programs have unsound code like array covariant (downcasting array members of the wrong type). tsc makes it easier to slip through these bugs.
And if tsc + jsdoc is good then the same question remains (do we really need the TypeScript language?)