--- name: AssemblyScript contributors: - ["Philippe Vlérick", "https://github.com/pvlerick"] - ["Steve Huguenin-Elie", "https://github.com/StEvUgnIn"] - ["Sebastian Speitel", "https://github.com/SebastianSpeitel"] - ["Max Graey", "https://github.com/MaxGraey"] filename: learnassemblyscript.ts --- __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](../typescript/) and [JavaScript](../javascript/). To test AssemblyScript's compiler, head to the [Playground](https://www.assemblyscript.org/editor.html#IyFydW50aW1lPXN0dWIKLyoqIENhbGN1bGF0ZXMgdGhlIG4tdGggRmlib25hY2NpIG51bWJlci4gKi8KZXhwb3J0IGZ1bmN0aW9uIGZpYihuOiBpMzIpOiBpMzIgewogIHZhciBhID0gMCwgYiA9IDEKICBpZiAobiA+IDApIHsKICAgIHdoaWxlICgtLW4pIHsKICAgICAgbGV0IHQgPSBhICsgYgogICAgICBhID0gYgogICAgICBiID0gdAogICAgfQogICAgcmV0dXJuIGIKICB9CiAgcmV0dXJuIGEKfQoKIyFodG1sCjx0ZXh0YXJlYSBpZD0ib3V0cHV0IiBzdHlsZT0iaGVpZ2h0OiAxMDAlOyB3aWR0aDogMTAwJSIgcmVhZG9ubHk+PC90ZXh0YXJlYT4KPHNjcmlwdD4KbG9hZGVyLmluc3RhbnRpYXRlKG1vZHVsZV93YXNtLCB7IC8qIGltcG9ydHMgKi8gfSkKICAudGhlbigoeyBleHBvcnRzIH0pID0+IHsKICAgIGNvbnN0IG91dHB1dCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdvdXRwdXQnKQogICAgZm9yIChsZXQgaSA9IDA7IGkgPD0gMTA7ICsraSkgewogICAgICBvdXRwdXQudmFsdWUgKz0gYGZpYigke2l9KSA9ICR7ZXhwb3J0cy5maWIoaSl9XG5gCiAgICB9CiAgfSkKPC9zY3JpcHQ+Cg==) where you will be able to type code, have auto completion and directly see the emitted WebAssembly. ```ts // There are many basic types in AssemblyScript, let isDone: boolean = false; let name: string = "Anders"; // but integer type come as signed (sized from 8 to 64 bits) let lines8: i8 = 42; let lines16: i16 = 42; let lines32: i32 = 42; let lines64: i64 = 42; // and unsigned (sized from 8 to 64 bits), let ulines8: u8 = 42; let ulines16: u16 = 42; let ulines32: u32 = 42; let ulines64: u64 = 42; // and float has two sizes possible (32/64). let rate32: f32 = 1.0 let rate64: f64 = 1.0 // But you can omit the type annotation if the variables are derived // from explicit literals let _isDone = false; let _lines = 42; let _name = "Anders"; // Use const keyword for constants const numLivesForCat = 9; numLivesForCat = 1; // Error // For collections, there are typed arrays and generic arrays let list1: i8[] = [1, 2, 3]; // Alternatively, using the generic array type let list2: Array = [1, 2, 3]; // For enumerations: enum Color { Red, Green, Blue }; let c: Color = Color.Green; // Functions imported from JavaScript need to be declared as external // @ts-ignore decorator @external("alert") declare function alert(message: string): void; // and you can also import JS functions in a namespace declare namespace window { // @ts-ignore decorator @external("window", "alert") function alert(message: string): void; } // Lastly, "void" is used in the special case of a function returning nothing export function bigHorribleAlert(): void { alert("I'm a little annoying box!"); // calling JS function here } // Functions are first class citizens, support the lambda "fat arrow" syntax // The following are equivalent, the compiler does not offer any type // inference for functions yet, and same WebAssembly will be emitted. export function f1 (i: i32): i32 { return i * i; } // "Fat arrow" syntax let f2 = (i: i32): i32 => { return i * i; } // "Fat arrow" syntax, braceless means no return keyword needed let f3 = (i: i32): i32 => i * i; // Classes - members are public by default export class Point { // Properties x: f64; // Constructor - the public/private keywords in this context will generate // the boiler plate code for the property and the initialization in the // constructor. // In this example, "y" will be defined just like "x" is, but with less code // Default values are also supported constructor(x: f64, public y: f64 = 0) { this.x = x; } // Functions dist(): f64 { return Math.sqrt(this.x * this.x + this.y * this.y); } // Static members static origin: Point = new Point(0, 0); } // Classes can be explicitly marked as extending a parent class. // Any missing properties will then cause an error at compile-time. export class PointPerson extends Point { constructor(x: f64, y: f64, public name: string) { super(x, y); } move(): void {} } let p1 = new Point(10, 20); let p2 = new Point(25); //y will be 0 // Inheritance export class Point3D extends Point { constructor(x: f64, y: f64, public z: f64 = 0) { super(x, y); // Explicit call to the super class constructor is mandatory } // Overwrite dist(): f64 { let d = super.dist(); return Math.sqrt(d * d + this.z * this.z); } } // Namespaces, "." can be used as separator for sub namespaces export namespace Geometry { class Square { constructor(public sideLength: f64 = 0) { } area(): f64 { return Math.pow(this.sideLength, 2); } } } let s1 = new Geometry.Square(5); // Generics // AssemblyScript compiles generics to one concrete method or function per set // of unique contextual type arguments, also known as [monomorphisation]. // Implications are that a module only includes and exports concrete functions // for sets of type arguments actually used and that concrete functions can be // shortcutted with [static type checks] at compile time, which turned out to // be quite useful. // Classes export class Tuple { constructor(public item1: T1, public item2: T2) { } } export class Pair { item1: T; item2: T; } // And functions export function pairToTuple (p: Pair): Tuple { return new Tuple(p.item1, p.item2); }; let tuple = pairToTuple({ item1: "hello", item2: "world" }); // Including references to a TypeScript-only definition file: /// // Template Strings (strings that use backticks) // String Interpolation with Template Strings let name = 'Tyrone'; let greeting = `Hi ${name}, how are you?` // Multiline Strings with Template Strings let multiline = `This is an example of a multiline string`; let numbers: Array = [0, 1, 2, 3, 4]; let moreNumbers: Array = numbers; moreNumbers[5] = 5; // Error, elements are read-only moreNumbers.push(5); // Error, no push method (because it mutates array) moreNumbers.length = 3; // Error, length is read-only numbers = moreNumbers; // Error, mutating methods are missing // Type inference in Arrays let ints = [0, 1, 2, 3, 4] // will infer as Array let floats: f32[] = [0, 1, 2, 3, 4] // will infer as Array let doubles = [0.0, 1.0, 2, 3, 4] // will infer as Array let bytes1 = [0 as u8, 1, 2, 3, 4] // will infer as Array let bytes2 = [0, 1, 2, 3, 4] as u8[] // will infer as Array let bytes3: u8[] = [0, 1, 2, 3, 4] // will infer as Array ``` ## Further Reading * [AssemblyScript Official website](https://www.assemblyscript.org/) * [AssemblyScript source documentation](https://github.com/AssemblyScript/website/tree/main/src) * [Source Code on GitHub](https://github.com/AssemblyScript/assemblyscript)