This assumes ES2015 knowledge.
// NUMBER
var count: number;
// BOOLEAN
var isDone: boolean = false;
// ANY
// Bypass type check
var anyObject: any;
// UNION
// For multiple types
var twoInOne: number | boolean;
var list: number[] = [1, 2, 3];
// same as above, alternate style;
var list: Array<number> = [1, 2, 3];
An array with a fixed number of elements;
var location: [number, number];
Friendly names to numeric values. A simple map.
enum Colour {Black, Green, Blue};
var myFavouriteColour: Colour = Colour.Blue;
console.log(myFavouriteColour); // 2
var colourName: string = Colour[myFavouriteColor];
console.log(colourName);
function exampleFunctionName(paramName: paramType): returnType {}
To declare a variable that holds a specific type of function;
let exampleFunctionName: (paramName: paramType) => returnType;
The above code ain't great. This is better solved with interfaces (more later);
interface ExampleFunctionInterface {
(paramName: paramType): returnType;
}
let exampleFunctionName: ExampleFunctionInterface;
Functions that don't return anything should use the void
type, which represents undefined
or null
;
function example(): void {}
function example(requiredParam: string, optionalParam?: number) {}
TypeScript is good at guessing the type of things, but sometimes it doesn't.
Similar to converting / casting to a different type, but without any checking or restructuring data.
Two styles;
Style number 1;
const notSure: any = "this could be anything";
const stringLength: number = (<string>notSure).length;
Note: This style does not work with JSX.
Style number 2;
const notSure: any = "this could be anything";
const stringLength: number = (notSure as string).length;
Setting an object type;
let square = <Square>{};
const [x, y] = [10, 50];
console.log(x); // 10
console.log(y); // 50
As parameters in a function;
function processColour([r, g, b]: [number, number, number]) {
console.log(r);
console.log(g);
console.log(g);
}
example(
param1: string,
{
option1 = false,
option2 = 'default',
}: {
option1?: boolean;
option2?: string;
} = {}
)
Some fancy examples;
let [first] = [1, 2, 3, 4];
let [first, ...rest] = [1, 2, 3, 4];
let [, second, , fourth] = [1, 2, 3, 4];
With objects and types;
let {a, b}: {a: string, b: number} = { a: "baz", b: 100 }
var exampleObject = {
propertyName: propertyType
} = {
propertyName: propertyValue
};
Or with assertions;
var exampleObject = {
propertyName: <propertyType> propertyValue
};
var exampleObject = {
propertyName: propertyValue as propertyType
};
return new Promise<type>(resolve => resolve('resolve must match type'));
<type>
is for the resoled value. Rejections are hardcoded to any
.
interface Person {
firstName: string;
lastName: string;
}
function sayHello(somebody: Person) {}
Optional properties and functions;
interface ExampleConfig {
foo?: string;
bar?: number;
exampleFunc: (paramName: paramType) => void;
exampleFuncSimple: () => void;
}
Indexable types. Key supports either number
or string
.
interface StringArray {
[index: number]: string;
}
let myStringArray: StringArray;
myStringArray = [ 'Bob', 'Fred' ];
A class can implement an interface;
class Example implements ExampleInterface {}
An interface describing one function;
interface ExampleFunc {
(param1: string, param2: number): boolean;
}
let myExampleFunc: ExampleFunc;
myExampleFunc = function(paramNameDoesNotHaveToMatch: string, onlyTheTypesMustMatch: number) {
// return a boolean
}
An object / class with a named function;
interface ExampleClassInterface {
exampleFunctionName(param: number);
}
class ExampleClass extends ExampleClassInterface {
exampleFunctionName(param: number) {
// ...
}
}
Interfaces can extend 1 or more interfaces;
interface ExampleInterface1 extends ExampleInterface2;
interface ExampleInterface1 extends ExampleInterface2, ExampleInterface3;
Instead of;
class Student {
name: string;
constructor(name: string) {
this.name = name;
}
}
Can do;
class Student {
constructor(public name: string) {}
}
Private members can only be accessed by the class.
Protected members can only be accessed by the class, and any class extending the class.
class Student {
constructor(private name: string) {}
}
These modifiers can be applied to members, not just parameters. Each member is public by default.
class Student {
fullName: string;
private secretName: string;
constructor(public firstName, public lastName) {
this.fullName = firstName + ' ' + lastName;
this.secretName = this.fullName + ' shhhh';
}
}
class Employee {
private _fullName: string;
get fullName(): string {
return this._fullName;
}
set fullName(newName: string) {
this._fullName = newName;
}
}
Abstract classes can not be instantiated, but can be extended.
Abstract methods must be implemented.
abstract class ExampleAbstractClass {
abstract exampleAbstractMethod(): void;
}
Provide type information for third party javascript code that is not in TypeScript. These libraries are known as 'ambient modules'.
File extension: .d.ts
.
Provides benefits of type checking, autocompletion, and documentation for all libraries.
Can be provided via npm modules as an item in package.json
.
The declare
keyword is used to declare ambient module API.
If you need to access an ambient declaration, a reference comment must be added to the top of the file;
/// <reference path="example" />
Typings is a package manager for finding and downloading type definitions.
Uses a file named typings.json
which stores ambient modules, and the source of the definition file.
This source can be from a Typings Registry (eg: DefinitelyTyped, GitHub, NPM, Bower, HTTP, and local files.
After running typings install
, an index.d.ts
file will be created within /typings
directory. This file stores all the "triple-slash" reference tags.
The file /typings/index.d.ts
is then pulled into the files
array inside tsconfig.json
.
For code that works with multiple types at once.
Imagine a function that returns what is passed in. What type do you set?
function returnMe(param: any): any {
return param;
}
This works, but isn't very specific.
We can dynamically capture the type of parameter, and then use it as a placeholder.
It is common to use <T>
meaning 'Type', but it could be anything.
function returnMe<T>(param: T): T {
return param;
}
Now, if passing in a type of 'number', it will be captured into T
, and the param type and return type will be set to string
.
let compilerKnowsThisIsAString = returnMe("this is a string");
Can be explicit if needed;
let compilerKnowsThisIsAString = returnMe<string>("this is a string");
interface ExampleGenericInterface {
<T>(param: T): T;
}
interface ExampleGenericInterface<T> {
(param: T): T;
}
When using the interface, need to specify the type;
let example: ExampleGenericInterface<number>;
class ExampleClass<T> {
add: (x: T, y: T) => T;
}
let example = new ExampleClass<number>();
Because <T>
can be anything, the compiler may throw errors when using .title
or .length
or whatever it may be. You are limited to properties that must exist on anything.
This is solved by extending an interface;
class ExampleClass<T extends Interface> {}
Declaration attached to class, method, accessor, property, or parameter.
To invoke;
@exampleDecorator thingToDecorate
Or on multiple lines;
@exampleDecorator
thingToDecorate
And the decorator;
function exampleDecorator(target) {
// do something with target
}
Allows decorator behaviour to be tweaked;
function exampleDecorator(configParam: boolean) {
return function(target) {
// do something with target, and configParam
}
}
Single line;
@exampleDecorator1 @exampleDecorator2 thingToDecorate
Multiple lines;
@exampleDecorator1
@exampleDecorator2
thingToDecorate
The order is strange;
function exampleDecorator() {
// Run top to bottom (1, 2)
return function(target) {
// Run bottom to top (2, 1)
}
}
- Parameters
- Methods
- Accessors
- Properties
- Parameters for constructor
- Class
class ExampleClass implements ExampleMixin, ExampleMixin2 {}
The implements
treats the classes as interfaces, so only the types (and not the implementation) is used.
Unfortunately, all properties and types must be manually added to the class to satisfy the compiler.
class ExampleMixin {
exampleFunction() {
return true;
}
}
class ExampleClass implements ExampleMixin {
exampleFunction: () => boolean;
}
The mixins also need to be manually applied;
applyMixins(ExampleClass, [ExampleMixin1, ExampleMixin2]);
function applyMixins(derivedCtor: any, baseCtors: any[]) {
baseCtors.forEach(baseCtor => {
Object.getOwnPropertyNames(baseCtor.prototype).forEach(name => {
derivedCtor.prototype[name] = baseCtor.prototype[name];
});
});
}