(Very Experimental) TypeScript Support in the Moddable SDK

Moddable believes JavaScript is the best language for building IoT products. We've heard from many developers that they agree with us, but that it is important to them to be able to use TypeScript. If you aren't familiar with TypeScript, it is a language created by Microsoft that adds features to JavaScript focused on type checking.

TypeScript is particularly clever because it is source code compatible with JavaScript, so you can incrementally adopt TypeScript features in your existing JavaScript code instead of learning a new programming language. TypeScript compiles directly to JavaScript source code which can be executed by any JavaScript engine, including the XS engine that powers the Moddable SDK. Because of that, it has always been possible to use TypeScript with the Moddable SDK, but until now it has required considerable work.

Moddable recently added very experimental support for TypeScript to the Moddable SDK. This is a powerful new capability with far-reaching implications. The initial integration into the Moddable SDK is the foundation to begin exploring that potential.

This article explains how to use TypeScript in your projects. If you aren't already familiar with TypeScript, the examples below will give you a first impression. The official TypeScript website is a good place to learn more.

How to Use TypeScript

TypeScript support has been integrated directly into the Moddable SDK build system, making it easy to use in existing projects and workflows.

Getting Set-Up

To use TypeScript, you first need to install the TypeScript command line tool so that it is available for use by the Moddable SDK build system. If you use Node, npm is a convenient way to install TypeScript:

npm install -g typescript

You'll also need to make sure you have the latest Moddable SDK installed. If you have an existing installation to update, follow the Keeping Up To Date document. If you are starting fresh, follow the Getting Started guide.

Building TypeScript Source Code

Using TypeScript in your projects is easy. Where you would normally have a source code file with a .js extension, use a .ts extension instead. For example, starting with the helloworld example in the Moddable SDK, rename main.js to main.ts and change the source code to the following:

let message = "Hello, world - TypeScript";
trace(message + "\n");

To build and run, use mcconfig as usual. The first line below builds and runs on the desktop simulator; the second, for an ESP8266.

mcconfig -d -m
mcconfig -d -m -p esp

Exploring TypeScript

There are many ways TypeScript can be used in your projects. This section shows a few simple examples to demonstrate some of the benefits of using TypeScript and the Moddable SDK together.

Typing Mistakes

The preceding example builds and runs, but it is just ordinary JavaScript. By changing the example slightly, you can see TypeScript's build time checking. In the following, the use of message in the call to trace has been misspelled as mesage.

let message = "Hello, world - TypeScript";
trace(mesage + "\n");

JavaScript catches this mistake, but only after you have have built the code, downloaded it to the embedded device, and executed it. That takes time. With TypeScript, the error is reported when you build.

main.ts:2:7 - error TS2552: Cannot find name 'mesage'. Did you mean 'message'?

2 trace(mesage + "\n");
         ~~~~~~

  main.ts:1:5
    1 let message = "Hello, world - sample";
           ~~~~~~~
    'message' is declared here.

Incorrect Arguments

TypeScript catches many other kinds of errors. For example, the following modification makes the mistake of passing no arguments to trace:

let message = "Hello, world - TypeScript";
trace();

Because TypeScript knows about the arguments to trace, it reports the mistake. The Type Declaration Files section below explains how TypeScript knows about the arguments.

main.ts:2:1 - error TS2554: Expected 1 arguments, but got 0.

2 trace();
  ~~~~~~~

  ../../xs/includes/xs.d.ts:2:3
    2  (log: string):void;
        ~~~~~~~~~~~
    An argument for 'log' was not provided.

New Language Features

TypeScript extends JavaScript with many new features. The following example uses the enum feature of TypeScript.

enum MQTT {
        CONNECT = 1,
        CONNACK,
        PUBLISH,
        PUBACK,
        PUBREC,
};

trace(MQTT.PUBLISH + "\n");
trace(MQTT[2] + "\n");

The enum declaration is straightforward. The first trace statement displays 3 on the console as you would expect. This enumeration is bi-directional, so the second trace statement displays the name of enumeration value 2, which is CONNACK.

To make this enumeration work in pure JavaScript, the TypeScript compiler outputs JavaScript code to create the enumeration:

var MQTT;
(function (MQTT) {
    MQTT[MQTT["CONNECT"] = 1] = "CONNECT";
    MQTT[MQTT["CONNACK"] = 2] = "CONNACK";
    MQTT[MQTT["PUBLISH"] = 3] = "PUBLISH";
    MQTT[MQTT["PUBACK"] = 4] = "PUBACK";
    MQTT[MQTT["PUBREC"] = 5] = "PUBREC";
})(MQTT || (MQTT = {}));

Debugging

When you run this enum example in xsbug, the Moddable SDK's JavaScript debugger, you want to see your original TypeScript source code, not the transpiled JavaScript code. The image below shows xsbug running the enum example.

As you can see, xsbug displays the original TypeScript source code. The breakpoint is at line 10 even though the JavaScript generated by TypeScript for the enum contains more lines than the original TypeScript. The remapping is done using a Source Map file output by the TypeScript compiler. It contains source file and line number mappings which xsbug uses to display the original TypeScript source code while executing the transpiled JavaScript.

The source map is not used to map variables so, for example, you see the full JavaScript version of the MQTT enumeration in the Locals pane.

Ways to Use TypeScript

Developers use TypeScript in their work flows in different ways. This section introduces three major uses of TypeScript that are valuable when using the Moddable SDK.

Editing

Many source code editors integrate support for TypeScript. These editors are able to offer helpful features even before you build your source code.

One benefit is suggestions while editing. In the image below, you can see Visual Studio Code offering autocomplete suggestions for the MQTT enumeration after the letter P has been typed.

Editors can also detect errors. For example, here it detects that an invalid value has been used from the enumeration.

Build Checks

The TypeScript compiler is able to identify many problems at build time that JavaScript cannot. Many of the errors it detects are not identified by JavaScript until the code executes. The build-time checks can lead to greater reliability in products as they detect errors much earlier in the process.

New Language Features

TypeScript brings many new features to JavaScript that are designed to increase the quality of code and the productivity of developers. The Moddable team looks forward to seeing which features embedded developers find useful in their projects.

Before committing to using a new language features in your product, do take care to evaluate its impact on performance, RAM use, and code size. The enum example illustrates this point. The code size of the TypeScript enum is considerably larger than a simple handwritten enumeration in JavaScript:

const MQTT = {
    CONNECT: 1,
    CONNACK: 2,
    PUBLISH: 3,
    PUBACK: 4,
    PUBREC: 5,
};

To support reverse mapping, the TypeScript version also uses more RAM. However, if it is preloaded, it uses no RAM at all.

Type Declaration Files

For TypeScript to perform its checks, it needs to know about the APIs your project uses. In the Moddable SDK, this is done using TypeScript declaration files. Declaration files are analogous to C header files: they describe an API but do not implement the API. In the case of the Moddable SDK, the implementation of the modules remains in JavaScript. The declaration files provide TypeScript the details of the APIs.

Creating declaration files is not easy. JavaScript is very flexible. Accurately describing that flexibility in a type declaration file is something of an art, requiring a deep understanding of TypeScript and practice. The Moddable team is new to TypeScript and has neither.

Fortunately, Bradley Farias of GoDaddy (and one of our colleagues in Ecma TC39) created a set of TypeScript declarations files for the Moddable SDK for his own use. Bradley generously contributed those to the Moddable SDK which gives us type declarations for thirty of the core modules. Many thanks to Bradley for his help.

The type declaration files are located in the typings directory at the root of the Moddable SDK. To use the typings files in your projects, include the typings manifest in your project's manifest.

{
    "include": [
        "$(MODDABLE)/examples/manifest_base.json",
        "$(MODDABLE)/examples/manifest_typings.json"
    ],
    "modules": {
        "*": "./main"
    },
}

The initial type declaration files are a great starting point to explore TypeScript with the Moddable SDK. They will need additional work to be ready for regular use: more modules need to be supported and some of the type declarations are incomplete. Contributing improvements to the type declarations is a great place for the community to advance the Moddable SDK.

Conclusion

Advocates of TypeScript often explain that its key benefit is helping to build more scalable, more reliable software. By detecting many problems earlier, that may well be true. Because TypeScript is designed to provide a gradual integration with JavaScript, all of the benefits of working in industry standard modern JavaScript are retained. Delivering better IoT products by building them using JavaScript is key to Moddable's mission. TypeScript fits well with that.

The core modules in the Moddable SDK will continue to be written in native JavaScript. This ensures that the modules can be understood by the largest possible group of developers, that only developers using TypeScript in their projects need to install and run it, and that no unexpected overhead is added to the code due to transpilation.

Moddable is excited to see how developers use TypeScript and will continue to improve the integration of TypeScript in the Moddable SDK. However, because TypeScript is still new to the Moddable team, the feedback and pull requests from developers with TypeScript experience are essential to driving that.