1
Show HN: TypeShim – .NET WebAssembly Meets TypeScript
I'm a big proponent of WebAssembly and .NET. When I found out .NET now runs in the browser on WASM with ánd without Blazor, I figured that could be something. Since Blazor is often too big of a step for TypeScript developers, I figured the recently added ability to include a .NET WASM app as a library in a JS bundle could be a good stepping stone for WASM to gain some ground in this JS-heavy web we have.
Using the JSExport/JSImport interop is relatively cumbersome, it only supports static methods, has no OOP concepts (like classes, just object handles) and it requires manually writing TypeScript definitions for the exported methods. So I decided to try and make some tooling that would improve the developer experience and reliability higher.
Enter TypeShim: a codegen tool that creates a seamless programming experience between .NET WebAssembly and TypeScript. Complete class level exports are translated to C# codegen to automatically define your JSExports/JSImports with a TypeScript class that wraps these methods. This creates proxies that look exactly like your C# classes and behave all the same, static/member, constructors, properties, methods, even things like reference equality. TypeShim supports all types that JSExport supports but includes your own classes in that list, so it provides a superset of what JSExport offers.
--
As Roslyn codegen wouldnt allow me to generate code that the JSExport codegen could consume, I had to make my own CLI codegen tool (which was a lot of fun). Thank Roslyn for exporting its APIs, allowing me to run my own compilation, which I could then use to build C# and TypeScript matching the classes that were marked for export.
It was also a good excuse to do some performance optimization work (because why not?!), NativeAOT turned out particularly suited for such short-running tooling and by taking care of a few bottlenecks found with PerfView, I managed to get codegen times down to ~100ms for projects with 100+ classes requiring codegen.
It took me down paths I hadnt expected to ever expected to end up at, like finding two bugs while E2E testing the solution, which would crash the .NET WASM runtime, which led me to dive into the dotnet/runtime repo and fix them. The dotnet team was grateful and very welcoming, inviting me to try fixing the same issues in the new .NET11 interop implementation which runs on the CoreCLR instead of mono. Great experience, I'll be going back for more TypeShim adjacent challenges: adding more types to the interop library.
--
Anyway, that was a bit of excitement about my recent open source activity. If you have a moment to look at TypeShim, maybe even leave a star, that would be greatly appreciated. But mostly I would love to hear your feedback!
Best, ArcadeMode