$('.awesome').show(); // Error: cannot find name `$`
declare var $:any;
$('.awesome').show(); // Okay!
declare var $:{
(selector:string): any;
};
$('.awesome').show(); // Okay!
$(123).show(); // Error: selector needs to be a string
[] + []; // JavaScript will give you ""
// (which makes little sense), TypeScript will error
// other things that are nonsensical in JavaScript
// - don't give a runtime error (making debugging hard)
// - but TypeScript will give a compile time error (making debugging unnecessary)
//
{} + []; // JS : 0, TS Error
[] + {}; // JS : "[object Object]", TS Error
{} + {}; // JS : NaN, TS Error
"hello" - 1; // JS : NaN, TS Error
function add(a,b) {
return
a + b; // JS : undefined, TS Error 'unreachable code detected'
}
class FooBase {
public x: number;
private y: number;
protected z: number;
}
// EFFECT ON INSTANCES
var foo = new FooBase();
foo.x; // okay
foo.y; // ERROR : private
foo.z; // ERROR : protected
// EFFECT ON CHILD CLASSES
class FooChild extends FooBase {
constructor() {
super();
this.x; // okay
this.y; // ERROR: private
this.z; // okay
}
}
class Adder {
constructor(public a: number) {}
// This function is now safe to pass around
add = (b: number): number => {
return this.a + b;
}
}
class ExtendedAdder extends Adder {
// Create a copy of parent before creating our own
private superAdd = this.add;
// Now create our override
add = (b: number): number => {
return this.superAdd(b);
}
}
var hello = "is it me you're looking for?";
for (var char of hello) {
console.log(char); // is it me you're looking for?
}
//...
class Frame implements IterableIterator<Component> {
private pointer = 0;
constructor(public name: string, public components: Component[]) {}
public next(): IteratorResult<Component> {
if (this.pointer < this.components.length) {
return {
done: false,
value: this.components[this.pointer++]
}
} else {
return {
done: true,
value: null
}
}
}
[Symbol.iterator](): IterableIterator<Component> {
return this;
}
}
//...
function iReturnPromiseAfter1Second(): Promise<string> {
return new Promise((resolve) => {
setTimeout(() => resolve("Hello world!"), 1000);
});
}
Promise.resolve(123)
.then((res) => {
// res is inferred to be of type `number`
return iReturnPromiseAfter1Second(); // We are returning `Promise<string>`
})
.then((res) => {
// res is inferred to be of type `string`
console.log(res); // Hello world!
});
// pause resume only once (and if) the promise
// returned from the function is settled
async function foo() {
try {
var val = await getMeAPromise();
console.log(val);
}
catch(err) {
console.log('Error: ', err.message);
}
}
import foo = require('foo');
// tells the TypeScript compiler to look
// for an external module declaration of the form:+
declare module "foo" {
// Some variable declarations
export var bar: number; /*sample*/
}
var boolArray: boolean[];
boolArray = [true, false];
console.log(boolArray[0]); // true
console.log(boolArray.length); // 2
boolArray[1] = true;
boolArray = [false, false];
boolArray[0] = 'false'; // Error!
boolArray = 'false'; // Error!
boolArray = [true, 'false']; // Error!
var name: {
first: string;
second: string;
};
name = {
first: 'John',
second: 'Doe'
};
var power: any;
// Takes any and all types
power = '123';
power = 123;
// Is compatible with all types
var num: number;
power = num;
num = power;
var num: number;
var str: string;
// These literals can be assigned to anything
num = null;
str = undefined;
function log(message): void {
console.log(message);
}
function reverse<T>(items: T[]): T[] {
var toreturn = [];
for (let i = items.length - 1; i >= 0; i--) {
toreturn.push(items[i]);
}
return toreturn;
}
var sample = [1, 2, 3];
var reversed = reverse(sample);
console.log(reversed); // 3,2,1
// Safety!
reversed[0] = '1'; // Error!
reversed = ['1', '2']; // Error!
reversed[0] = 1; // Okay
reversed = [1, 2]; // Okay
Another example:
/** A class definition with a generic parameter */
class Queue<T> {
private data = [];
push = (item: T) => this.data.push(item);
pop = (): T => this.data.shift();
}
/** Again sample usage */
const queue = new Queue<number>();
queue.push(0);
queue.push("1"); // ERROR : cannot push a string. Only numbers allowed
// ^ if that error is fixed the rest would be fine too
function formatCommandline(command: string[]|string) {
var line = '';
if (typeof command === 'string') {
line = command.trim();
} else {
line = command.join(' ').trim();
}
// Do stuff with line: string
}
function extend<T, U>(first: T, second: U): T & U {
let result = <T & U> {};
for (let id in first) {
result[id] = first[id];
}
for (let id in second) {
if (!result.hasOwnProperty(id)) {
result[id] = second[id];
}
}
return result;
}
var x = extend({ a: "hello" }, { b: 42 });
// x now has both `a` and `b`
var a = x.a;
var b = x.b;
// tuple type
var nameNumber: [string, number];
// Okay
nameNumber = ['Jenny', 8675309];
// Error!
nameNumber = ['Jenny', '867-5309'];
type StrOrNum = string|number;
// Usage: just like any other notation
var sample: StrOrNum;
sample = 123;
sample = '123';
// Just checking
sample = true; // Error!
declare module "jquery";
And then you can import it in your file as needed:
import * as $ from "jquery";
enum CardSuit {
Clubs,
Diamonds,
Hearts,
Spades
}
// Sample usage
var card = CardSuit.Clubs;
// Safety
card = "not a member of card suit"; // Error : string is not assignable to type `CardSuit`
// variable annotation
var sampleVariable: { bar: number }
// function parameter
function foo(sampleParameter: { bar: number }) { }
function padding(all: number);
function padding(topAndBottom: number, leftAndRight: number);
function padding(top: number, right: number, bottom: number, left: number);
// Actual implementation that is a true representation of all the cases the function body needs to handle
function padding(a: number, b?: number, c?: number, d?: number) {
if (b === undefined && c === undefined && d === undefined) {
b = c = d = a;
}
else if (c === undefined && d === undefined) {
c = a;
d = b;
}
return {
top: a,
right: b,
bottom: c,
left: d
};
}
interface Foo {
bar: number;
bas: string;
}
var foo = {} as Foo;
// ahhhh .... forget something?
interface Foo {
bar: number;
bas: string;
}
var foo = <Foo>{
// the compiler will provide autocomplete for properties of Foo
// But it is easy for the developer to forget adding all the properties
// Also this code is likely to break if Foo gets refactored (e.g. a new property added)
};
var x: { foo: number, [x: string]: any };
x = { foo: 1, baz: 2 }; // Ok, `baz` matched by index signature
class Foo {
foo = 123;
common = '123';
}
class Bar {
bar = 123;
common = '123';
}
function doStuff(arg: Foo | Bar) {
if (arg instanceof Foo) {
console.log(arg.foo); // OK
console.log(arg.bar); // Error!
}
if (arg instanceof Bar) {
console.log(arg.foo); // Error!
console.log(arg.bar); // OK
}
console.log(arg.common); // OK
console.log(arg.foo); // Error!
console.log(arg.bar); // Error!
}
doStuff(new Foo());
doStuff(new Bar());
var x: { foo: number, [x: string]: any };
x = { foo: 1, baz: 2 }; // Ok, `baz` matched by index signature
type CardinalDirection =
"North"
| "East"
| "South"
| "West";
function move(distance: number, direction: CardinalDirection) {
// ...
}
move(1,"North"); // Okay
move(1,"Nurth"); // Error!
function foo(config: {
readonly bar: number,
readonly bas: number
}) {
// ..
}
let config = { bar: 123, bas: 123 };
foo(config);
// You can be sure that `config` isn't changed 🌹
interface Square {
kind: "square";
size: number;
}
interface Rectangle {
kind: "rectangle";
width: number;
height: number;
}
type Shape = Square | Rectangle;
function area(s: Shape) {
if (s.kind === "square") {
// Now TypeScript *knows* that `s` must be a square ;)
// So you can use its members safely :)
return s.size * s.size;
}
else {
// Wasn't a square? So TypeScript will figure out that it must be a Rectangle ;)
// So you can use its members safely :)
return s.width * s.height;
}
}
let foo:{ [index:string] : {message: string} } = {};
/**
* Must store stuff that conforms the structure
*/
/** Ok */
foo['a'] = { message: 'some message' };
/** Error: must contain a `message` or type string. You have a typo in `message` */
foo['a'] = { messages: 'some message' };
/**
* Stuff that is read is also type checked
*/
/** Ok */
foo['a'].message;
/** Error: messages does not exist. You have a typo in `message` */
foo['a'].messages;
const colors = {
red: 'red',
blue: 'blue'
}
type Colors = keyof typeof colors;
let color: Colors;
color = 'red'; // okay
color = 'blue'; // okay
color = 'anythingElse'; // Error