Earlier this year I had a play with Microsoft’s new compile to JavaScript language, TypeScript. Every man and his dog has a compile to JavaScript solution these days. TypeScript’s angle appears to be to provide optional static typing over JavaScript and some ES6 functionality while compiling out to ES3 by default. It provides a class based syntax similar to C#’s and seems to be aimed at developer’s attempting to scale out JavaScript based solutons.
Last year I ported Elm’s Mario sample to F#, which ended up looking similarly concise. I tried both FunScript and WebSharper for compiling F# to JavaScript, and both worked well:
So I thought I’d try the sample out in TypeScript as a way to get a feel for the language.
TypeScript Interfaces
In F# I defined a type for Mario using a record:
// Definition
type mario = { x:float; y:float; vx:float; vy:float; dir:string }
// Instantiation
let mario = { x=0.; y=0.; vx=0.; vy=0.; dir="right" }
In TypeScript I used an interface which looks pretty similar syntactically:
// Definition
interface Character {
x: number; y: number; vx: number; vy: number; dir: string
};
// Instantiation
var mario = { x:0, y:0, vx:0, vy:0, dir:"right" };
TypeScript transcompiles this to a JavaScript associative array using object notation:
var mario = { x: 0, y: 0, vx: 0, vy: 0, dir: "right" };
Composition
For me the cute part of the Elm and F# versions was using the record “with” syntax and function composition, i.e.
let jump (_,y) m = if y > 0 && m.y = 0. then { m with vy = 5. } else m
let gravity m = if m.y > 0. then { m with vy = m.vy - 0.1 } else m
let physics m = { m with x = m.x + m.vx; y = max 0. (m.y + m.vy) }
let walk (x,_) m =
{ m with vx = float x
dir = if x < 0 then "left" elif x > 0 then "right" else m.dir }
let step dir mario = mario |> physics |> walk dir |> gravity |> jump dir
I couldn’t fine either of those features available out-of-the-box in TypeScript so I resorted to imperative code with mutation and procedures:
function walk(velocity: CursorKeys.Velocity, character: Character) {
character.vx = velocity.x;
if (velocity.x < 0) character.dir = "left";
else if (velocity.x > 0) character.dir = "right";
}
function jump(velocity:CursorKeys.Velocity, character:Character) {
if (velocity.y > 0 && character.y == 0) character.vy = 5;
}
function gravity(character: Character) {
if (character.y > 0) character.vy -= 0.1;
}
function physics(character: Character) {
character.x += character.vx;
character.y = Math.max(0, character.y + character.vy);
}
function verb(character: Character): string {
if (character.y > 0) return "jump";
if (character.vx != 0) return "walk";
return "stand";
}
function step(velocity: CursorKeys.Velocity, character:Character) {
walk(velocity, mario);
jump(velocity, mario);
gravity(mario);
physics(mario);
}
The only difference between the TypeScript and the resultant JavaScript is the type annotations.
HTML Canvas
TypeScript provides typed access to JavaScript libraries via type definition files. The majority appear to be held on a personal github repository.
Note: both FunScript and WebSharper can make use of these type definition files to provide types within F# too.
Among other things this lets you get typed access over things like the HTML canvas element albeit with some funky casts:
var canvas = <HTMLCanvasElement> document.getElementById("canvas");
canvas.width = w;
canvas.height = h;
This has some value, but you do have to rely on the definition files being kept up-to-date.
Conclusions
On the functional reactive side TypeScript didn't appear to offer much value add in comparison to Elm or F#.
To be honest, for a very small app, I couldn’t find any advantages to using TypeScript over vanilla JavaScript. I guess I’d need to build something a lot bigger to find any.
Sample source code: https://bitbucket.org/ptrelford/mario.typescript