Gil Amran
How to use TypeScript
How to use TypeScript
The main purpose of a type system is to reduce possibilities for bugs in computer programs by defining interfaces between different parts of a computer program, and then checking that the parts have been connected in a consistent way."
Wikipedia
var name = "John";var name: string = "John";function greet(name) {
console.log(`Hello ${name}`);
}function greet(name: string) {
console.log(`Hello ${name}`);
}function promote(person) {
// code
}function promote(person: {name: string, age: number}) {
// code
}1889
Punch cards
1948
Assembly
1972
C
1995
Java
1997
JavaScript
2015
JavaScript - ES6
var x: string;
var y: number;
var z: boolean;
var foo: any;
var bar; // Same as "any"
var x;
var y;
var z;
var foo;
var bar;
var a: any[];
var b: string[];
var p: Product[];
var a;
var b;
var p;
function addTax(tax:number, product: Product) {
.
.
.
}
function addTax(tax, product) {
.
.
.
}
var func : (name: string) => number;
function process(x: () => string){
x().toLowerCase();
}
var func;
function process(x){
x().toLowerCase();
}function greet(name: string): void {
console.log(`Hello ${name}`);
}function greet(name) {
console.log(`Hello ${name}`);
}function process(x: {a: string; b: number}) {
return x.a.length;
}interface IThing {
a: number;
b: string;
}
function process(x: IThing){
return x.a.length;
}
function process(x){
return x.a.length;
}
function process(x){
return x.a.length;
}
interface IProduct {
name : string;
price : number;
}
function hasName(product: IProduct){
return product.name.length > 0;
}
var isNamed = hasName({name: 'iPhone', price: 1000});
function hasName(product){
return product.name.length > 0;
}
var isNamed = hasName({name: 'iPhone', price: 1000});interface IPerson {
age : number;
name : string;
address? : string; // <-- optional field
}
function getName(p: IPerson){
return p.name;
}
var name = getName({age:10, name:'Me'});interface IUsersMap {
[userId: string]: IUser;
}
var usersMap: IUsersMap;
var user = usersMap['038373832']; // user is IUser
interface IPerson {
age : number;
name : string;
address : string;
walk(distance:number): number; // <-- a Function
}
interface IPerson {
age : number;
name : string;
address : string;
walk(distance:number): number;
(): string; // <-- a Function
}npm i -g typescript
tsc exercise.ts -wlet str = `I am ${age} years old`;var str = "I am " + age + " years old";Object.assign(foo, bar);Object.assign(foo, bar);namespace model {
export function init() {
}
export function getState {
}
function thisIsPrivate() {
}
}var model;
(function (model) {
function init() {
}
model.init = init;
function getState() {
}
model.getState = getState;
function thisIsPrivate() {
}
})(model || (model = {}));
class Person {
constructor(firstName: string, lastName: string) {
}
}
const person: Person = new Person('John', 'Doe');class Person {
constructor(firstName: string, lastName: string) {
}
walk(distance: number): void {
}
calculateStepSize(): void {
}
}
const person: Person = new Person('John', 'Doe');class Person {
constructor(firstName: string, lastName: string) {
}
public walk(distance: number): void {
}
private calculateStepSize(): void {
}
}
const person: Person = new Person('John', 'Doe');
person.walk(5); // ok
person.calculateStepSize(); // Errorclass Person {
public age: number;
constructor(firstName: string, lastName: string) {
}
public walk(distance: number): void {
}
private calculateStepSize(): void {
}
}
const person: Person = new Person('John', 'Doe');
class Person {
public age: number;
private firstName: string;
private lastName: string;
constructor(firstName: string, lastName: string) {
this.firstName = firstName;
this.lastName = lastName;
}
public walk(distance: number): void {
}
private calculateStepSize(): void {
}
}
const person: Person = new Person('John', 'Doe');
class Person {
public age: number;
constructor(private firstName: string, private lastName: string) {
}
public walk(distance: number): void {
}
private calculateStepSize(): void {
}
}
const person: Person = new Person('John', 'Doe');
class Person {
public age: number;
constructor(private firstName: string, private lastName: string) {
}
public walk(distance: number): void {
}
private calculateStepSize(): void {
}
get name():string {
return this.firstName + ' ' + this.lastName;
}
set age(value: number): void {
this.age = value;
}
}declare var _ : any;
_.last([1, 2, 3]); // 3
_.last([1, 2, 3]); // 3declare var _: {
last(arr: any[]): any;
}
_.last([1, 2, 3]); // 3
_.last([1, 2, 3]); // 3
_.last([1, 2, 3]); // ERROR: Cannot find name '_'+4000 contributors
+30K commits
+11K stars
Thousands of definition files
node.d.ts
npm install @types/lodashnode_modules/@types auto included
versioning
declare const Math: {
random(): number;
sqrt(x: number): number;
sin(x: number): number;
.
.
.
};
21K lines of ambient declarations
eval, parseInt, encodeURI
Math, Date, RegExp
Full DOM declarations
And many more...
interface Math {
/** The mathematical constant e. This is Euler's number, the base of natural logarithms. */
E: number;
/** The natural logarithm of 10. */
LN10: number;
/** The natural logarithm of 2. */
LN2: number;
/** The base-2 logarithm of e. */
LOG2E: number;
/** The base-10 logarithm of e. */
LOG10E: number;
/** Pi. This is the ratio of the circumference of a circle to its diameter. */
PI: number;npm install @types/nodevar x = 3; // x is a number
class MyClass {
name = "Foo"; // name is a string
}
function foo(value = false) { // value is a boolean
}
function calc() {
return 55; // calc returns a number
}
var x = calc(); // x is also a number
interface IHuman {
age: number;
walk(distance:number):void;
}
var man : IHuman = {
age : 120,
walk: function(distance) {
console.log(distance); // distance inferred to be a number
}
}
window.onmousedown = function(mouseEvent) {
// mouseEvent inferred as MouseEvent
console.log(mouseEvent.button);
};
var x = 3; // x is a number
x = "45"; // compiler error
var foo = {};
foo.description = 'I am FOO'; // compiler error
var x : any = 3; // x can be anything
x = "45";
var foo : any = {};
foo.description = 'I am FOO'; // compiler is happy
var x; // x is any forever
x = '45'; // x is still any
function process(x) { // x is any
return x+x*3; // return type is any
}
process(42); // this does not change the type of x
var x: any;
if (typeof x === 'string') {
console.log(x.subtr(1)); // Error
}
// x is still any here
x.unknown(); // OK
class Animal { name:string }
class Cat extends Animal { meow() { } }
var pet: Animal = new Cat();
if (pet instanceof Cat) {
pet.meow(); // OK
} else {
pet.meow(); // Error
}
function formatCommandline(command: string[] | string) {
var line = '';
if (typeof command === 'string') {
line = command.trim();
} else {
line = command.join(' ').trim();
}
// Do stuff with line: string
}
interface ISerializable {
serialize(): string;
}
interface ILoggable {
log(): void;
}
class Person {
}
const all: ISerializable & ILoggable & Person = someObject;
type paddingType = string | number;
function padLeft(value: string, padding: paddingType) {
// ...
}
type CardinalDirection =
"North"
| "East"
| "South"
| "West";
function move(distance: number, direction: CardinalDirection) {
// ...
}
move(1,"North"); // Okay
move(1,"Nurth"); // Error!
enum CardSuit {
Clubs,
Diamonds,
Hearts,
Spades
}
// Sample usage
var card = CardSuit.Clubs;
// Safety
card = "not a member of card suit"; // Error
interface Person {
name: string;
age: number;
location: string;
}
type K1 = keyof Person; // "name" | "age" | "location"
type K2 = keyof Person[]; // "length" | "push" | "pop" | "concat" | ...
type K3 = keyof { [x: string]: Person }; // string
interface IPerson {
readonly age: number;
readonly height: number;
}
interface ReadonlyArray<T> {
...
interface ReadonlyMap<K, V> {
...
interface ReadonlySet<T> {
...
function first<T>(arr: T[]): T {
return arr[0];
}
let foo = first([1, 2, 3]); // foo must be a number
let bar = first(['A', 'B', 'C']); // bar must be a string
function later(): Promise<number> {
// code ...
}
later().then(result => console.log(result)); // result is a number
// from lib.es6.d.ts
type Partial<T> = {
[P in keyof T]?: T[P];
};
type PartialPerson = Partial<Person>;
interface Person {
name: string;
age: number;
location: string;
}
interface PartialPerson {
name?: string;
age?: number;
location?: string;
}
// from lib.es6.d.ts
type Readonly<T> = {
readonly [P in keyof T]: T[P];
};
/**
* Usage
*/
let foo: Readonly = { 0: 123, 2: 345 };
console.log(foo[0]); // Okay (reading)
foo[0] = 456; // Error (mutating): Readonly
interface Task {
id: string,
name: string,
assignee: string,
contacts: any[], //for brevity
associatedJob: string,
submissionDate: string,
allocatedTime: number,
expectedCompletion: string,
invoiceNumber: string,
invoiceDueDate: string,
comment: string,
taskAddress: string
...
...
}
type PartialTask = Pick<Task, 'id' | 'name' | 'contacts'>