TypeScript (TS) adds types and tooling to JavaScript (JS) to improve code quality and catch errors earlier. It is a superset of JS that compiles to plain JS. Key features include type annotations, classes, interfaces, generics and tooling like Visual Studio Code with IntelliSense. While TS adds complexity, it improves code organization, documentation and catches errors at compile time rather than runtime. The type system has limits but TS is a useful alternative to other languages for large JS projects.
3. Software Developer @ ASA (hotel PMS software)
Particular interests:
● API design
● some functional programming
and a little category theory ;)
Programming Languages:
● Java
● JavaScript/TypeScript
Matthias Perktold
4. Mario A. Santini
Software Developer in Telecommunication field
like Free Software and solving problems
love to work with a lot of different languages:
JavaScript, Java, Rust, Go… and now TypeScript!
5. The web had needed a script language
World Wide Web was meant to share knowledge
not for applications
…
in order to be able to share you need a little help from
something more dynamic than just tags...
6. Why JavaScript
● the script for the web should have been small
● the script for the web should have no need to interact with anything outside
the browser
● you just need something to check forms data and react on events
That’s why pretty much all the other
existing languages don’t fit!
10. It was enough for the small part...
It is not for the wide one:
● Namespace: only global or function scope
● Code organization: no module/package nothing standard
● OO without classes: no design patterns reference
● Poor tooling
11. ECMAScript
● The standard moves faster and faster but only recently
● Browser vendors have to implement new specifications
● Cannot break the past
● Not all the issues are addressed
14. Why TypeScript?
● It is JavaScript with types
● All JavaScript code is already TypeScript
● Easy for Java / C# people
● Not intrusive
● Allows all the new cool stuff
● Sponsored by Google and used in Angular 2 >>
15. Why it make JavaScript better
● Strong types with dynamic inference
● You can define your own types
● You can use generics, with unions, intersection and
more…
● You don’t need to add all together
● You can exit any time with no a big deal
● Oh… and it made the tooling much more cool!
17. Type Annotations
export interface Named {
name: string;
}
export function greet({ name }: Named): string {
return `Hello, ${name}!`;
}
const john: Named = { name: "John" };
const greetingForJohn: string = greet(john);
const greetingForEmma = greet({ name: "Emma" });
document.body.innerHTML = `
<h2>${greetingForJohn}</h2>
<h2>${greetingForEmma}</h2>
`;
Compiled to ECMAScript 6:
export function greet({ name }) {
return `Hello, ${name}!`;
}
const john = { name: "John" };
const greetingForJohn = greet(john);
const greetingForEmma = greet({ name: "Emma" });
document.body.innerHTML = `
<h2>${greetingForJohn}</h2>
<h2>${greetingForEmma}</h2>
`;
18. Classes and More Types
import { greet } from "./type-annotations";
class Person {
public readonly name: string;
constructor(
public readonly firstName: string,
public readonly lastName: string,
public readonly interests: string[] = []
) {
this.name = `${firstName} ${lastName}`;
}
public isInterestedIn(topic: string): boolean {
const idx: number = this.interests.indexOf(topic);
return idx >= 0;
}
}
const john: Person = new Person(
"John", "Doe",
["Politics", "Sports", "Programming"]
);
john.firstName = "Fred";
// -> Error: Cannot assign to 'firstName'
because it is a read-only property.
type ShowFn = (arg: any) => void;
const log: ShowFn = arg => console.log(arg);
log(john);
// Structural Typing
// -> Person is assignable to Named
log(greet(john));
19. Inheritance and Access Modifiers
enum State { Initial, Started, Stopped };
interface LifeCycle {
readonly state: State;
start(): void;
stop(): void;
}
abstract class AbstractLifeCycle
implements LifeCycle
{
private _state = State.Initial;
get state() { return this._state; }
start() {
if (this.state === State.Started)
return;
this.onStart();
this._state = State.Started;
}
stop() { /* similar to start */ }
protected abstract onStart(): void;
protected abstract onStop(): void;
}
No package scope
No final classes or methods
20. Inheritance and Access Modifiers - cont.
class Clock extends AbstractLifeCycle {
private intervalID?: number; // ? denotes optional property
protected onStart() {
this.intervalID = setInterval(
() => console.log(new Date),
1000
);
}
protected onStop() {
clearInterval(this.intervalID);
}
}
const clock = new Clock();
clock.start();
The compiler ensures we override all abstract
methods and properties.
21. Function Overloads
function plus(n1: number, n2: number): number;
function plus(s1: string, s2: string): string;
function plus<T>(a1: T[], a2: T[]): T[];
function plus(a1: any, a2: any): any {
return typeof a1 === "number"
? a1 + a2
: a1.concat(a2);
}
const n = plus(1, 2); // 3
const s = plus("1", "2"); // "12"
const a = plus([1], [2]); // [1, 2]
const x = plus(1, "2"); // Compiler Error
23. Tuples are already part of JS
interface Point {
x: number;
y: number;
}
const point: Point = { x: 3, y: 5 };
const entries: [string, number][] = Object.entries(point); // [ ["x",3], ["y",5] ]
for (const [key, value] of entries)
console.log(`${key} = ${value}`);
// logs:
// x = 3
// y = 5
24. Union Types
function getInstant(): Date | number {
return Date.now();
}
const inst = getInstant();
const date: Date = typeof inst === "number"
? new Date(inst) // known to be number here
: inst; // known to be Date here
console.log(date.toLocaleDateString());
25. Intersection Types
function withName<T>(obj: T, name: string): T & Named {
return { ...obj, name };
}
function greetPoint(point: Point & Named): string {
return greet(point)
+ ` You are at ${point.x}/${point.y}.`;
}
const origin: Point = { x: 0, y: 0 };
console.log(greetPoint(withName(origin, "Origin")));
26. Nullability
declare function parseDate(str: string): Date | null;
const d1: Date = null; // Error
const d2: Date = parseDate("2000-01-01"); // Error
const d3: Date | null = parseDate("2000-01-01"); // OK
console.log(d3.toLocaleDateString()); // Error
if (d3)
console.log(d3.toLocaleDateString()); // OK
Always use compiler flag “strictNullChecks”!
27. Type Guards
function isPoint(obj: any): obj is Point {
return typeof obj === "object"
&& typeof obj.x === "number"
&& typeof obj.y === "number";
}
function invalidPoint(p: any): never {
throw new Error(`Invalid point: ${p}`);
}
const requirePoint = (p: unknown) => isPoint(p) ? p : invalidPoint(p);
const loaded: unknown = JSON.parse(localStorage.get("current_point"));
let currentPoint: Point;
currentPoint = loaded; // Error
currentPoint = requirePoint(loaded); // OK
28. Discriminated Unions
aka Tagged Unions, Algebraic Data Types
type Expr<V> = Constant<V> | Plus<V> | Times<V>;
interface Constant<V> { tag: "Constant", value: V }
interface Plus<V> { tag: "Plus", left: Expr<V>, right: Expr<V> }
interface Times<T> { tag: "Times", left: Expr<T>, right: Expr<T> }
function evalNum(expr: Expr<number>): number {
switch (expr.tag) {
case "Constant": return expr.value;
case "Plus": return evalNum(expr.left) + evalNum(expr.right);
case "Times": return evalNum(expr.left) * evalNum(expr.right);
}
}
29. Index Types and Mapped Types
type PointKeys = keyof Point; // "x" | "y"
type XOfPoint = Point["x"]; // number
function mapVals<T, V>(
obj: T,
fn: (v: T[keyof T]) => V
): {
[k in keyof T]: V
} {
const res: any = {};
for (const [k, v] of Object.entries(obj))
res[k] = fn(v);
return res;
}
const mapped = mapVals(
{ x: 1, y: 2 },
v => String(v)
); // { x: string, y: string }
console.log(mapped); // { x: "1", y: "2" }
30. Conditional Types
type NonNullable<T> = T extends null | undefined ? never : T;
function requireNonNull<T>(val: T): NonNullable<T> {
if (val == null)
throw new TypeError();
return val as NonNullable<T>;
}
const nonNullDate: Date = requireNonNull(parseDate("2000-01-01"));
console.log(nonNullDate.toLocaleDateString());
Conditional types distribute over union types:
NonNullable<Date | null>
== NonNullable<Date> | NonNullable<null>
== Date | never
== Date
31. Putting it Together
type Pick<T, K extends keyof T> = {
[P in K]: T[P];
};
type Exclude<T, U> = T extends U ? never : T;
type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;
declare function pick<T, K extends keyof T>(obj: T, ...keys: K[]): Pick<T, K>;
declare function omit<T, K extends keyof T>(obj: T, ...keys: K[]): Omit<T, K>;
const pickedX = pick(point, "x"); // { x: number }
const omittedX = omit(point, "x"); // { y: number }
32. Limits of the type system
type Func<I, O> = (arg: I) => O;
// Works, but only for a limited number of arguments
function pipe<A, B, C>(f1: Func<A, B>, f2: Func<B, C>): Func<A, C>;
function pipe<A, B, C, D>(f1: Func<A, B>, f2: Func<B, C>, f3: Func<C, D>): Func<A, D>;
function pipe<A, B, C, D, E>(f1: Func<A, B>, f2: Func<B, C>, f3: Func<C, D>, f4: Func<D, E>): Func<A, D>;
function pipe<A, B, C, D, E, F>(f1: Func<A, B>, f2: Func<B, C>, f3: Func<C, D>, f4: Func<D, E>, f5: Func<E, F>):
Func<A, F>;
function pipe(...fns: Func<any, any>[]): Func<any, any> {
return arg => fns.reduce((res, f) => f(res), arg);
}
const fThenG = pipe(f, g); // x => g(f(x))
33. Limits of the type system 2
No higher-kinded types
// Collects the results of a list of actions.
// Like Promise.all(), but works for any Monad, not only Promise.
// Possible in Haskell, but not in TS
sequence :: Monad m => [m a] -> m [a]
37. Type Definitions
Declare types of JS code in separate files without changing the original code
Allows to work with native JS code in TS in a typesafe way
// greet.js (original JS code)
export function greet({ name }) {
return `Hello, ${name}!`;
}
// greet.d.ts (typings of greet.js)
export interface Named {
name: string;
}
export declare function greet({ name }: Named): string;
41. Conclusion
Is not going to save the day / despite it introduces types, use of last specs and
improved the tooling
Adopting it has a cost:
it is another language / even not so intrusive
few people know it compared to Javascript / it’s growing, but meanwhile...
not all library are types ready / you can fix what you need easely
Typescript improved the tooling for Javascript too!
It is better than the other alternatives so far...
42. Conclusion 2
Pros
● only adds, doesn’t change
● type safety
● catches errors at compile time
● structured documentation
● types guide an API user
● facilitates tooling
Cons
● more to learn, hiring more difficult
● complexity
● doesn’t replace testing
● verbosity
● burden on the API implementor
● type system has its limits
43. Riferimenti
SoCraTeN http://www.socraten.org/
Where to start: http://www.typescriptlang.org/
TypeScript in 5 minutes: https://www.typescriptlang.org/docs/handbook/typescript-in-5-minutes.html
Manual: https://www.typescriptlang.org/docs/handbook/basic-types.html
Reference: https://github.com/microsoft/TypeScript/blob/master/doc/spec.md
TypeScript github: https://github.com/microsoft/TypeScript
An honest view: https://medium.com/javascript-scene/the-typescript-tax-132ff4cb175b