AssemblyScript compiles a variant of TypeScript (basically JavaScript with types) to WebAssembly using Binaryen. It generates lean and mean WebAssembly modules while being just an npm install
away.
This article will focus only on AssemblyScript extra syntax, as opposed to TypeScript and JavaScript.
To test AssemblyScript’s compiler, head to the Playground where you will be able to type code, have auto completion and directly see the emitted WebAssembly.
1// There are many basic types in AssemblyScript,
2let isDone: boolean = false;
3let name: string = "Anders";
4
5// but integer type come as signed (sized from 8 to 64 bits)
6let lines8: i8 = 42;
7let lines16: i16 = 42;
8let lines32: i32 = 42;
9let lines64: i64 = 42;
10
11// and unsigned (sized from 8 to 64 bits),
12let ulines8: u8 = 42;
13let ulines16: u16 = 42;
14let ulines32: u32 = 42;
15let ulines64: u64 = 42;
16
17// and float has two sizes possible (32/64).
18let rate32: f32 = 1.0
19let rate64: f64 = 1.0
20
21// But you can omit the type annotation if the variables are derived
22// from explicit literals
23let _isDone = false;
24let _lines = 42;
25let _name = "Anders";
26
27// Use const keyword for constants
28const numLivesForCat = 9;
29numLivesForCat = 1; // Error
30
31// For collections, there are typed arrays and generic arrays
32let list1: i8[] = [1, 2, 3];
33// Alternatively, using the generic array type
34let list2: Array<i8> = [1, 2, 3];
35
36// For enumerations:
37enum Color { Red, Green, Blue };
38let c: Color = Color.Green;
39
40// Functions imported from JavaScript need to be declared as external
41// @ts-ignore decorator
42@external("alert")
43declare function alert(message: string): void;
44
45// and you can also import JS functions in a namespace
46declare namespace window {
47 // @ts-ignore decorator
48 @external("window", "alert")
49 function alert(message: string): void;
50}
51
52// Lastly, "void" is used in the special case of a function returning nothing
53export function bigHorribleAlert(): void {
54 alert("I'm a little annoying box!"); // calling JS function here
55}
56
57// Functions are first class citizens, support the lambda "fat arrow" syntax
58
59// The following are equivalent, the compiler does not offer any type
60// inference for functions yet, and same WebAssembly will be emitted.
61export function f1 (i: i32): i32 { return i * i; }
62// "Fat arrow" syntax
63let f2 = (i: i32): i32 => { return i * i; }
64// "Fat arrow" syntax, braceless means no return keyword needed
65let f3 = (i: i32): i32 => i * i;
66
67// Classes - members are public by default
68export class Point {
69 // Properties
70 x: f64;
71
72 // Constructor - the public/private keywords in this context will generate
73 // the boiler plate code for the property and the initialization in the
74 // constructor.
75 // In this example, "y" will be defined just like "x" is, but with less code
76 // Default values are also supported
77
78 constructor(x: f64, public y: f64 = 0) {
79 this.x = x;
80 }
81
82 // Functions
83 dist(): f64 { return Math.sqrt(this.x * this.x + this.y * this.y); }
84
85 // Static members
86 static origin: Point = new Point(0, 0);
87}
88
89// Classes can be explicitly marked as extending a parent class.
90// Any missing properties will then cause an error at compile-time.
91export class PointPerson extends Point {
92 constructor(x: f64, y: f64, public name: string) {
93 super(x, y);
94 }
95 move(): void {}
96}
97
98let p1 = new Point(10, 20);
99let p2 = new Point(25); //y will be 0
100
101// Inheritance
102export class Point3D extends Point {
103 constructor(x: f64, y: f64, public z: f64 = 0) {
104 super(x, y); // Explicit call to the super class constructor is mandatory
105 }
106
107 // Overwrite
108 dist(): f64 {
109 let d = super.dist();
110 return Math.sqrt(d * d + this.z * this.z);
111 }
112}
113
114// Namespaces, "." can be used as separator for sub namespaces
115export namespace Geometry {
116 class Square {
117 constructor(public sideLength: f64 = 0) {
118 }
119 area(): f64 {
120 return Math.pow(this.sideLength, 2);
121 }
122 }
123}
124
125let s1 = new Geometry.Square(5);
126
127// Generics
128// AssemblyScript compiles generics to one concrete method or function per set
129// of unique contextual type arguments, also known as [monomorphisation].
130// Implications are that a module only includes and exports concrete functions
131// for sets of type arguments actually used and that concrete functions can be
132// shortcutted with [static type checks] at compile time, which turned out to
133// be quite useful.
134// Classes
135export class Tuple<T1, T2> {
136 constructor(public item1: T1, public item2: T2) {
137 }
138}
139
140export class Pair<T> {
141 item1: T;
142 item2: T;
143}
144
145// And functions
146export function pairToTuple <T>(p: Pair<T>): Tuple<T, T> {
147 return new Tuple(p.item1, p.item2);
148};
149
150let tuple = pairToTuple<string>({ item1: "hello", item2: "world" });
151
152// Including references to a TypeScript-only definition file:
153/// <reference path="jquery.d.ts" />
154
155// Template Strings (strings that use backticks)
156// String Interpolation with Template Strings
157let name = 'Tyrone';
158let greeting = `Hi ${name}, how are you?`
159// Multiline Strings with Template Strings
160let multiline = `This is an example
161of a multiline string`;
162
163let numbers: Array<i8> = [0, 1, 2, 3, 4];
164let moreNumbers: Array<i8> = numbers;
165moreNumbers[5] = 5; // Error, elements are read-only
166moreNumbers.push(5); // Error, no push method (because it mutates array)
167moreNumbers.length = 3; // Error, length is read-only
168numbers = moreNumbers; // Error, mutating methods are missing
169
170// Type inference in Arrays
171let ints = [0, 1, 2, 3, 4] // will infer as Array<i32>
172let floats: f32[] = [0, 1, 2, 3, 4] // will infer as Array<f32>
173let doubles = [0.0, 1.0, 2, 3, 4] // will infer as Array<f64>
174let bytes1 = [0 as u8, 1, 2, 3, 4] // will infer as Array<u8>
175let bytes2 = [0, 1, 2, 3, 4] as u8[] // will infer as Array<u8>
176let bytes3: u8[] = [0, 1, 2, 3, 4] // will infer as Array<u8>