type annotations
Anders Hejlsberg@Build2016: Big JavaScript codebases tend to become "read-only".
Recently published survey on the state of JavaScript
let obj: string;
obj = 'yo';
// Error: Type 'number' is not assignable to type 'string'.
obj = 10;
// types can be inferred (return type)
function sayIt(what: string) {
return `Saying: ${what}`;
}
const said: string = sayIt(obj);
class Sayer {
// mandatory
what: string;
constructor(what: string) {
this.what = what;
}
// return type if you want to
sayIt(): string {
return `Saying: ${this.what}`;
}
}
let obj: string;
obj = 'yo';
// Error: number: This type is incompatible with string
obj = 10;
function sayIt(what: string) {
return `Saying: ${what}`;
}
const said: string = sayIt(obj);
class Sayer {
what: string;
constructor(what: string) {
this.what = what;
}
sayIt(): string {
return `Saying: ${this.what}`;
}
}
Those basic features help with documentation, refactoring, and IDE support
function foo(num: number) {
if (num > 10) {
return 'cool';
}
}
console.log(foo(100).toString());
// error: call of method `toString`.
// Method cannot be called on possibly null value
console.log(foo(100).toString());
// to fix this, we need to check the result
const fooed: string|void = foo(100);
if (fooed) {
fooed.toString();
}
Types are non-nullable by default in flow
function foo(num: number) {
if (num > 10) {
return 'cool';
}
}
// same as flow
const fooed: string|void = foo(100);
if (fooed) {
fooed.toString();
}
// or tell the compiler we know better (in this case we actually do)
fooed!.toString();
Only applies to TypeScript 2.x
Only works when strictNullChecks option is checked
All types nullable by default in TypeScript 1.x
can be anything, not specified
can selectively disable type checking
function func(a: any) {
return a + 5;
}
// cool
let r1: string = func(10);
// cool
let r2: boolean = func('wat');
Types can be parameterized by others
Most common with collection types
let cats: Array<Cat> = []; // can only contain cats
let animals: Array<Animal> = []; // can only contain animals
// nope, no cat
cats.push(10);
// nope, no cat
cats.push(new Animal('Fido'));
// cool, is a cat
cats.push(new Cat('Purry'));
// cool, cat is a sub type of animal
animals.push(new Cat('Purry'));
Both Flow and TypeScript support upper, but not lower bounds
class Person {
name: string;
}
class Dog {
name: string;
}
let dog: Dog = new Dog();
// nope, nominal type compatibility violated
let person: Person = dog; // ERROR: Dog: This type is incompatible with Person
// same problem
let person: Person = { // ERROR: object literal: This type is incompatible with Person
name: "Olli"
};
class Person {
name: string;
}
class Dog {
name: string;
}
let dog: Dog = new Dog();
// yes, correct, as structurally compatible
let person: Person = dog;
// same thing, also correct
let person: Person = {
name: "Olli"
};
// this is fine as nominal typing only applies to Flow classes
let namedObject: NamedObject = dog;
// same thing, also fine
let namedObject: NamedObject = {
name: "Olli"
};
// not fine in either
let namedObject: NamedObject = {
firstName: "Olli"
};
// cool in flow, but TypeScript wants perfect match with object literal
// ERROR: Object literal may only specify known properties,
// and 'firstName' does not exist in type 'NamedObject'.
let namedObject: NamedObject = {
name: "Olli",
firstName: "Olli"
};
TypeScript has special support for classes
Makes it easier for people coming from Java/C++/C#
Flow does not feature those or any other syntactic sugar, as it is a checker only
Starting from 2016.3