So it's typed as any in TypeScript and it's not really that useful. So we started this journey in an effort to seamlessly integrate Rust functions for data structures into TypeScript apps with WebAssembly. And it looks like we should give up. Unless maybe there is a magical tool that could help us by generating type safety and ergonomic bindings.
Well, thankfully that tool exists. It's called tspy and I honestly love it. It supports everything we've seen so far but doesn't need any manual casting and it comes with strong late type bindings. We'll see in a second that we're going to need a little bit more macros to make things work. But still a huge improvement over the previous approaches. Notice that also we need to install tspy with the JS feature flag, which will give us a native JavaScript integration. Otherwise it will use JSON serialization by default.
As a demonstration, we will readapt the previous example using Enum variants, which we wanted to be translated to target unions in TypeScript. So, we see that we need to derive SerDes traits, as well as the new tspy trait. We also need to use a new tspy macro to tell Wasp bind to compile some data types, you know, a data type that is otherwise unsupported by Wasp binding. In fact, Wasp ABI stands for WebAssembly Application Binary Interface and it describes how to call functions between languages in WebAssembly. We then define the familiar either variant with a twist that is common to all the approaches that use SerDe. We need to tell Rust how to serialize this in a variant because, you know, this could happen in a plethora of ways and to get idiomatic tag unions like the ones we see on the right, we have to tell Rust that the variant name should be associated with its dominant key, namely underscore tag, and that the content of the variant, which is defined between the constructor parenthesis, should be associated to a property named value. We can then define a function that for instance takes an instance on either and returns its string representation. Notice that it doesn't really require us to write any type casting boilerplate code and it translates to a clean TypeScript definition. Just like SerD vs BindGen, we can define an either value in JavaScript without needing any constructor. We can just create it on spot as a dictionary. But this time we get TypeScript guarantees, so we can leverage TypeScript's compiler to avoid writing typos in our data types. So let's wrap up what we've learned so far.
WebAssembly is here to remain, and it's good for CPU-intensive tasks that would otherwise be too slow in pure JavaScript, or for parting already existing complex logic to the web. Think about Figma. However, it currently provides almost no input-output support. So if you need to interact with the outside world from your functions, you'd better stick with the NAPI for the moment. We've iterated through several approaches to port Rast functions to Node.js and observed there are limitations or awkward developer experience, especially for TypeScript ads. We've finally seen that the best solution for type-safe bindings, TSFI is still relatively new. One caveat is that its source code heavily relies on macro magic, right? And that could be a deal-breaker for someone. Also for any set of the approach, and that includes TSFI, you can't just use generic containers like vectors or hash maps directly in a function that you bind to WebAssembly. You actually first need to specify the generic type. So, you have to do, you have to say, a vector of strings and then you have to wrap it into a struct or enum variant that you then expose to SerDe via the serialized or de-serialized traits and then you use that in your function. And if you want to see some example of TSFI being used in the wild, you can check a PR online that introduced WebAssembly support to Lira, a full-text search engine written in TypeScript by Mikhail Eriva, which I believe spoke here at Node Congress as well. Michael, oh, well, sorry, Mikhail Eriva was quite happy with the performance improvements. And that's it for me. I'm Bertos Ghebel, you can find me on Twitter and GitHub, you can also find additional material and code samples for this talk on my repository, node-congress-2023.
Comments