TypeScript to WebAssembly: The What, The How And The Why

The learning curve for WASM is very steep. This sometimes scares people away from it. AssemblyScript is a perfect way of writing compatible code if you already know TypeScript.

Fernando Doglio
Bits and Pieces
Published in
7 min readSep 30, 2020

--

Assembly and assembly-like languages are very powerful in the sense that they allow for fantastic performance given how close they are to their execution environment (i.e the Virtual Machine they run on and so on), but at the same time, they usually lack everything we love about programming languages: the actual high-level abstractions such as IF statements, FOR loops, CLASSES and what not.

So using these low-level languages has a very steep learning curve, given how different they are from other languages. And that is what happens with WebAssembly (or WASM as it is also known), which is an assembly-type language that browsers now support (or should I say, are starting to support). You can use it when you really need that performance boost, the problem? It looks like this:

Now, don’t worry if you’re trying to interpret that code and you’re not getting anywhere, WASM’s purpose is not to be manually written but instead, compiled to from other languages. So, you could be using Rust code and compile it into WASM or even Go. This means you can write web-compatible code in other languages and have browsers execute it. What?! Yes, you read that right, that is WASM’s main goal, to have a low-level interface for any other programming language.

Then again, if you want to use WASM, you need to learn one of these languages that now have a compiler to WASM and one such language is TypeScript (or almost) thanks to WebAssemblyScript.

Tip: Share your reusable components between projects using Bit (Github). Bit makes it simple to share, document, and organize independent components from any project.

Use it to maximize code reuse, collaborate on independent components, and build apps that scale.

Bit supports Node, TypeScript, React, Vue, Angular, and more.

Example: exploring reusable React components shared on Bit.dev

What is WebAssemblyScript then?

Now that you know what WebAssembly is, you understand how you need another language, and WebAssemblyScript is just that: essentially a stricter version of TypeScript (if you can believe that) that can easily be compiled into WASM.

What do I mean by stricter? Well, TypeScript by design has several limitations compared to JavaScript when it comes to types and everything related to them because well, that’s the whole point about it!

However, it still benefits from a lot of the dynamism and flexibility from JavaScript which is hard to efficiently compile ahead of time. Remember that JavaScript is compiled during execution time and we can’t do that here, we need to compile it first, and then execute that output.

So with WebAssemblyScript we can’t do the following things we’re used to with TypeScript:

  • No more any or undefined types. You need to be explicit when it counts, meaning there is some type inference, but you can’t allow for dynamic behavior here.
  • You can’t create type unions (i.e string | number ).
  • Objects need to be strictly typed. Meaning you can’t just create literal objects and start adding properties to them, you have to either use a Map or a proper class with pre-defined types.
  • All modules execute inside a secured sandbox, which means there is no direct access to any external APIs. This is great, until you realized this means no direct DOM access for front-end projects. You have to manually import and exports the functions you want to use or share with the outside world of your module.
  • As of now, the current implementation of WebAssemblyScript only allows for numeric values to be exchanged between your modules and the outside world (i.e the runtime where your code is running). This means strings, arrays and object exchange is out of the question (as of now). They do have workarounds, which are also limited to strings and arrays, but they’re just that: workarounds. The actual solutions are still under development.
  • Closures are not yet implemented. This is a feature they’re pretty much interested in having but considering it’s still not yet implemented, you have to be sure to not use any type of closures in your code. This might be harder said that done, considering how much a part of the language these constructs are.

Their recommendation when it comes to the lack of support for closures, is to implement something like this:

Either use a for loop or move the declaration of sum outside of the computeSum function, like this:

My personal recommendation would be to go for the second option and try to avoid a functional approach as much as possible, that way you’ll stay way from closures.

How to use WebAssemblyScript?

If you’re still interested in checking out this project, then you’re in luck, because using it is relatively easy.

First of all, you’ll need to have Node installed, because we’re going to be installing a couple of npm packages.

First, create a new project folder, and once inside it, run:

$ npm init

This will initiate your project, it’ll ask a few questions, you can leave the default values for all of them. Then, once that is out of the way, run the following commands:

$ npm install --save @assemblyscript/loader
$ npm install --save-dev assemblyscript

That will install everything you need to get started, once both commands have finished, you can run:

$ npx asinit .

This will create the required folder structure with all the boilerplate code in place.

As you can see, quite a lot of files and folders are created. With this done, you’ll have to install the new dependencies added to the project with npm install .

This is it, once you’ve installed all new dependencies, you’re actually ready to get started. I know it sounds like a lot of setting up, but that’s it. You can now start adding code inside the assembly folder and once you’re ready to compile it, just run:

$ npm run asbuild 

And look for the compiled code inside the build folder. A sample code is already included so you can run this command right out of the box and see what it does.

Finally, if you want to test out your compiled code, you can create an index.html file in the root of the project and add the following code to it:

Again, there is a lot of boilerplate code required to just load your WASM code and use it, but think of the power you’re accessing through it. Notice how we’re using the WebAssembly object out of nowhere, this was tested on Chrome and works great, which means this is a native feature of your browsers you’re not using.

Why would you use WebAssemblyScript?

After all of this, all the restrictions and all the boilerplate code required, why would you go through all the trouble of writing semi-typescript to then have to load it in such an awkward way?

Well, there are benefits after all, specially to WebAssembly, you have to remember that because you’re compiling the code before execution, you have the following benefits:

  • A degree of security that no dynamic language can give you. If your code compiles, you can be sure it won’t let you crash it due to a problematically typed variable.
  • Reliable optimization. Remember, we’re not dealing with the JIT here, that requires execution time to understand how to optimize your code. Your compiled code will be optimized in the right places, everytime you execute it, no matter what.
  • Performance-wise, if we’re talking about heavy computation code, then it’s much better than JavaScript.

And in particular, if you add on top of all that the fact that you don’t have to learn a completely new language (such as Rust or C) in order to compile it to WASM, WebAssemblyScript starts making total sense. This is a perfect way of bridging the gap for JavaScript developers who’re not used to other languages.

Granted, learning a completely new language has its benefits as well, but if time is not on your side, taking advantage of an already familiar syntax is always great!

So to answer the question, why would you use WebAssemblyScript?, well if you’re dealing with a heavy computation-based problem such as:

  • Video editing
  • Music applications
  • VR-related projects
  • Image recognition
  • Game development (some parts at least)
  • Crypto-related algorithms
  • …etc

Then maybe, WASM and WebAssemblyScript in particular could be a good option.

If on the other hand, you’re dealing with usual JavaScript (or TypeScript) related projects such as a website, or a REST API, then no, there is no need to go through all the hustle required to add WASM code to your project (if you’re having performance issues in these projects, the problems are somewhere else, not on the runtime).

Of course, there are limitations to WebAssemblyScript as I’ve already mentioned and the project will require time to be fully done. But if you think of it as an entryway to the WASM world, after you’ve tested the power you can access and eventually making the switch to maybe compiling Rust or C into WASM (at least in the meantime while this project is not finished yet), then it’s definitely a very good option.

Have you used WebAssemblyScript or even WASM before? What was your experience with it? Would you recommend it?

Leave a comment down below and share your experience, I’d love to know how you’re using this technology on your day-to-day!

Learn More

--

--

I write about technology, freelancing and more. Check out my FREE newsletter if you’re into Software Development: https://fernandodoglio.substack.com/