General documentation / cheat sheets for various languages and services

1.0

It’s unclear what features were introduced with this release, or if it was just an assurance of stability.

1.1 CTP (Community Technology Preview)

This release offers no new features, but improves compilation speed by around 4x.

1.3

protected

TODO

Tuple types

var bounds: [number, number, number, number] = [10, 10, 100, 100];
var top_left = new Point(bounds[0], bounds[1]);

Generic tuple types are awkward. Even with type aliases from 1.4, the following is invalid:

type MatchResult<T> = [RegExp, T]  // Syntax Error!

Instead, we must use the bulkier interface syntax:

export interface MatchResult<T> extends Array<RegExp | T> {
  0: RegExp;
  1: T;
}

1.4 (sneak peek)

Union Types

function join(text: string | string[]) {
  return Array.isArray(text) ? text.join('') : text;
}

Type Guards

Use typeof and instanceof to type-check at runtime, and the TypeScript compiler will (should) infer the more specific type for the duration of the check’s scope.

function add1(arg: number | string) {
  if (typeof arg === "number") {
    return arg + 1;
  }
  else {
    return arg + 'one';
  }
}

This works only on union types, not on a type hierarchy, but you can specify a class and its subclasses as a union type when needed.

Type Aliases

type ErrorCallback = (error?: Error) => void;

Const Enums

Unlike normal enums, Position below will not appear in the Javascript output.

const enum Position { Outside, Beginning, Inside };
var current_position = Position.Outside;

Let/Const

function main() {
  for (let index = 0; index < 10; x++) {
    console.log(index.toFixed());
  }
  for (let index = 'a'; index.length < 10; index += '!') {
    console.log(index);
  }
}

Template Strings

var point = { x: 10, y: 240 };
console.log(`Drawing point at (${point.x}, ${point.y})`);

1.5-Alpha

ES6 module syntax

import * as util from "util-enhanced";
import { format, inspect } from "util";

Suppose ndarray.ts has an export default class NDArray { ... }. We could import the NDArray class with import NDArray from "ndarray" while allowing other exports to be imported by wildcard or by name.

Destructuring

var [left, right] = pair.split('=');

In function parameters:

function move({x, y}, dx: number, dy: number) {
  return {x: x + dx, y: y + dy};
}
var originalPoint = {x: 10, y: 10};
var movedPoint = move(originalPoint, 30, 40);
console.log('current location:', movedPoint);
// outputs: "movedPoint == {x: 40, y: 50}"

It will also destructure classes:

class Point {
  constructor(public x: number, public y: number) { }
}
var pointInstance = new Point(-5, -5);
console.log('current location:', move(pointInstance, 10, 10));
// outputs: "current location: { x: 5, y: 5 }"

Decorators

Decorators are defined as functions and can be applied, with @myDecorator or @myDecorator('message') syntax, to class definitions, properties within class definitions, functions, or function parameters. Depending on the target, the decorator function should implement one of these signatures:

Examples

Memoized getter. Definition:

function memoize<T>(target: Object, propertyKey: string, descriptor: TypedPropertyDescriptor<T>) {
  var get = descriptor.get;
  var memoizedPropertyKey = `_memoized_${propertyKey}`;
  descriptor.get = function() {
    if (!this.hasOwnProperty(memoizedPropertyKey)) {
      this[memoizedPropertyKey] = get.call(this);
    }
    return this[memoizedPropertyKey];
  }
  return descriptor;
}

Application:

class NumberSeries {
  constructor(public value: number) { }

  @memoize
  get numberOfDigits(): number {
    console.log('Getting the total number of digits in all natural numbers < %d', this.value);
    var digits = '';
    for (var i = 0; i < this.value; i++) {
      digits += i.toFixed(0);
    }
    return digits.length;
  }
}

Execution:

var million = new NumberSeries(1000000);
console.error(million.numberOfDigits);
// immediately outputs: 'Getting the total number of digits in all natural numbers < 1000000'
// short pause, then outputs: '5888890'
console.error(million.numberOfDigits);
// immediately outputs: '5888890'

References:

1.5-Beta

Decorator Metadata

Requires the “reflect-metadata” package, npm install reflect-metadata, which provides type declarations in a file named reflect-metadata.d.ts in its root directory.

/// <reference path="../node_modules/reflect-metadata/reflect-metadata.d.ts" />

Importing it exposes a new global variable, Reflect.

import 'reflect-metadata';

Metadata is defined via the Reflect.defineMetadata(metadataKey: any, metadataValue: any, target: Object) method.

Create a simple class decorator to facilitate the metadata definition:

function ClassPriority(priority: number) {
  return function(target: Object) {
    Reflect.defineMetadata('priority', priority, target);
  }
}

Apply it to a couple of types:

@ClassPriority(1)
class StringValidator {
  // ...
}
@ClassPriority(2)
class NumberValidator {
  // ...
}

Instantiate one like so:

var validator = new NumberValidator(/* ... */);

And inspect its class metadata via Reflect.getMetadata(metadataKey: any, target: Object): any:

console.log('validator priority:', Reflect.getMetadata('priority', validator.constructor));
// outputs: 'validator priority: 2'

1.6

React/JSX

Replace the extension .ts with .tsx and you can use JSX markup directly, as in a .jsx file with Babel, which compiles to React.createComponent(...) or React.createElement(...) calls.

Class expressions

Classes can be declared anonymously and used immediately.

I don’t yet know where this would be useful.

Abstract classes

Replace class with abstract class to keep it from being instantiated directly. Otherwise, it is inheritable and extensible as usual.

Prefix class methods with abstract to require that subclasses implement it.

So, it’s kind of like an interface with defaults.

Intersection types

C: A & B is like saying interface C extends A, B { ... }, but more concise, doesn’t require declaring a distinct new type, and works for generics.

Type checking functions (a.k.a. “User defined type guards”)

If typeof and instanceof aren’t cutting it, you can declare a function that returns a type assertion like function(id: string): id is GUID { ... } and then when you use that function in a conditional, id will have the type GUID for the scope of that conditional.

Before, you would have had to declare a new variable with a <GUID><any>id type coercion inside that conditional if you wanted to benefit from your type check.

Excess properties

Interfaces now defines an object’s maximal properties. Before, it only described the necessary properties. E.g.:

interface Person { first: string; last: string }

Before, this would be fine:

var current_user: Person = { first: 'Chris', last: 'Brown', age: 39 }

Now, that will cause a type error.

Module resolution

When using --module commonjs output, the TypeScript compiler will look for type declarations in a variety of places:

1. Check in node_modules for <module name>.d.ts
2. Search node_modules\<module name>\package.json for a typings field
3. Look for node_modules\<module name>\index.d.ts
4. Then we go one level higher and repeat the process

I think this is the most promising of the TypeScript 1.6 features/improvements in making tooling better.

Generic type aliases

Type aliases can now have type parameters. Pretty basic stuff, I’m not sure why this wasn’t in the original type aliasing implementation.

1.7

async / await (target: ES6 only)

Use async function myFunc(...) {...} instead of function myFunc(...) {...} to declare an asynchronous function.

Polymorphic this

Most useful for method chaining. If an interface or class has a this type, any subclasses or implementations will effectively replace that this type with their own type.

For example, EventEmitter can be declared as:

declare module 'events' {
  export class EventEmitter {
      on(event: string, listener: Function): this;
      /* ...all the other methods... */
  }

And I can inherit it like so:

import {EventEmitter} from 'events';
class SelfClosingElementParser extends EventEmitter {
  readString(xmlString: string): this {
    xmlString.match(/<(.+) />/g, match => {
      this.emit('data', match[1]);
    });
  }
}

And chain calls like this:

new SelfClosingElementParser()
.on('data', tag => console.log(tag))    // <-- this was fine prior to 1.7
.readString(rawString)                  // <-- but this would have raised an type error,
                                        //     since .on() would have returned an EventEmitter,
                                        //     not the SelfClosingElementParser.

target: ES6

Useful if you want to compile to ES6 except for its module system (which Node.js v4 doesn’t support), specifying a different module system, like “commonjs”.

** operator

** is the new Math.pow as of ES7. I.e., base ** exponent === Math.pow(base, exponent).

General TypeScript notes

“Constant signatures” can be used to provide types for events:

export interface ImapFetch extends NodeJS.EventEmitter {
    on(event: string, listener: Function): this;
    on(event: 'message', listener: (message: ImapMessage) => void): this;
    on(event: 'error', listener: (error: Error) => void): this;
}

Recommended .gitignore (assuming all JavaScript files are generated from TypeScript):

*.js
*.d.ts

Recommended .npmignore:

*.ts
!*.d.ts
tsconfig.json

Extra .npmignore entries for packages using Travis CI:

.travis.yml
tests/

Recipes

@bind (decorator)

Add this to your tsconfig.json:

{
  "compilerOptions": {
    "experimentalDecorators": true,
    ...
  },
  ...
}

Then, with the following definition of bind in scope:

function bind<T extends Function>(target: Object,
                                  propertyKey: string | symbol,
                                  descriptor: TypedPropertyDescriptor<T>): TypedPropertyDescriptor<T> | void {
  return {
    configurable: true,
    get(this: T): T {
      const value = descriptor.value.bind(this)
      Object.defineProperty(this, propertyKey, {
        value,
        configurable: true,
        writable: true,
      })
      return value
    },
  }
}

You can use it like this:

class NumberInput extends Component {
  @bind
  onChange(ev: FormEvent<HTMLInputElement>) {
    const input = ev.currentTarget
    const value = parseInt(input.value, 10)
    this.setState({value})
  }
  render() {
    const {label = 'Pick a number'} = this.props
    const {value = 0} = this.state
    return (
      <label>
        <div><b>{label}</b></div>
        <input type="number" value={value} onChange={this.onChange} />
      </label>
    )
  }
}