TypeScript en 20 mn

Loïc Mathieu -        @loicmathieu

Introduction

Introduction

  • Langage créé par Anders Hejlsberg en 2012
  • Projet open-source maintenu par Microsoft (Version actuelle 3.2)
  • Propose une extension du JavaScript apportant le typage
  • Influencé par JavaScript, Java et C#

Introduction

  • Phase de compilation nécessaire pour générer du JavaScript
  • Ajout de nouvelles fonctionnalités au langage JavaScript
  • Rétrocompatible: Tout programme JavaScript est un programme TypeScript

Principales fonctionalités

  • Typage et inférence de type
  • Enum, Tuples...
  • Classes / Interfaces / Héritage
  • Génériques
  • Les fichiers de définitions
  • Décorateurs

Le compilateur

  • TypeScript se présente sous la forme d'un paquet NPM

  • Le paquet contient un CLI qui permet d'utiliser le compilateur : tsc

  • Toutes les options de compilation sont accessibles via le CLI
  • Le plus souvent, on utilisera un fichier de configuration tsconfig.json
npm install --global typescript

Le Typage

Les variables

var variableName: VariableType = value;

let variableName2: VariableType = value;

const variableName3: VariableType = value;

Et en JS ?

//the type
const Model = use('Model')
//the variable
const Item = use('App/Item/Models/Item')

//what should be ...
assert.isTrue(Item.prototype instanceof Model)

Les types primitifs

const isDone: boolean = false;

const height: number = 6;

const phone_number: number = 555_734_2231;

const milion: number = 1_000_000;

const name: string = 'Carl';

const names: string[] = ['Carl', 'Laurent'];

const notSure: any = 4;

const alsoNotSure = 5; //-> implicit number
let x!: number;
initialize();

// erreur sans le !
console.log(x + x);

function initialize() {
    x = 10;
}

undefined et !

unknow (3.0)

function f21<T>(pAny: any, pNever: never, pT: T) {
    let x: unknown;
    x = 123;
    x = new Error();
    x = x;
    x = pAny;
    x = pNever;
    x = pT;
}

function f22(x: unknown) {
    let v1: any = x;
    let v2: unknown = x;
    let v3: object = x;  // Error
    let v4: number = x;  // Error
    let v6: {} = x;  // Error
    let v7: {} | null | undefined = x;  // Error
}

Les fonctions

//regular fonction
function namedFunction(arg1: string, arg2: number): string {
  return `${arg1} - ${arg2}`;
}

//arrow fonction
let myFunc: (arg1: string, arg2: number) => string;

//new 3.0 with safe typings
type Function<A extends any[], R> = (...args: A) => R;

Supporte : param par défaut, rest parameters, décomposition, ...

Les paramètres optionnels

function fn(name: string, surname?: string): void {
  console.log(name, surname);
}

fn(); //-> compilation error
fn('carl'); //-> 'carl' undefined
fn('carl', 'boss'); //-> 'carl' 'boss'

Un paramètre peut être optionnel :

  • Utilisation du caractère ? avant le type
  • L'ordre de définition est très important
  • Aucune implication dans le code JavaScript généré
  • S'il n'est pas défini, le paramètre aura la valeur undefined

Spécialisation de fonction

function fn(param: string): number;
function fn(param: number): string;
function fn(param: any): any {
  if (typeof param === "number") {
    return "string";
  } else {
    return 42;
  }
}

Array

//litteral 
const list: number[] = [1, 2, 3];

//Array
const list: Array<number> = [1, 2, 3];

Tuple

const tuple: [string, number] = ['Zenika', 10];

const [name, age] = tuple;

Enum

//with default index
enum Music { Rock, Jazz, Blues };

const c: Music = Music.Jazz;

//with defined index
enum Music { Rock = 2, Jazz = 4, Blues = 8 };

const c: Music = Music.Jazz;

//getting the name of the enum
const style: string = Music[Music.Jazz]; //Jazz

Et en JS ?

const MappingType = {
  /*
    default type : will be mapped as following :
    'boolean:boolean', 'integer:long', 'number:double', 'object:object', 'string:text'
    array will not be mapped to a type as it's not needed for elasticsearch
  */
  DEFAULT: 'default',
  // no mapping will be created for this field and the field will not be included in the index
  NOT_SEARCHABLE: 'not_searchable',
  // the field will be included in the index but not analyzed : match only on the full value (type='keyword')
  NOT_ANALYZED: 'not_analyzed'
}

Inférence de type

Basé sur :

  • Les types de données à l'initialisation des variables
  • Les valeurs par défaut des arguments de fonctions
  • Le type de données retourné dans une fonction

 

Duck typing : 

Si je vois un oiseau qui vole comme un canard, cancane comme un canard, et nage comme un canard, alors j'appelle cet oiseau un canard

 

Classes

Classes

Se base sur les classes de ES2015 et les enrichit

class Person {
    constructor(
        firstName: string,
        lastName: string = "Dupont"
    ) 
}

const person: Person = new Person("Michel");

Méthode

class Person {
  sayHello(message: string): void {
    console.log(`Hello ${message}`);
  }
}

const person: Person = new Person();
person.sayHello('World'); //-> 'Hello World'

Propriété

Définit dans le corps de la classe,
se comporte comme un let

class Person {
  firstName: string;
  lastName: string = "Dupont";
  age: number;
  hobbies: string[];
}

const person: Person = new Person();
console.log(person.lastName); //-> 'Dupont'

Modificateur de visibilité

class Person {
  private message: string = 'World';

  public sayHello(): void {
    console.log(`Hello ${this.message}`);
  }
}

const person: Person = new Person();
person.sayHello(); //-> 'Hello World'
console.log(person.message); // compilation error
// Property 'message' is private and only accessible 
// within class 'Person'.
  • public (le défaut)
  • protected
  • private
  • readonly

statique

class Person {
  static message: string = 'World';

  static sayHello(): void {
    console.log(`Hello ${Person.message}`);
  }
}

const person: Person = new Person();
Person.sayHello(); //-> 'Hello World'
console.log(Person.message); // -> 'World'
person.sayHello(); // compilation error
// Property 'sayHello' does not exist on type 'Person'

héritage (ES2015)

class Person {
  constructor() {}
  speak() {}
}

class Child extends Person {
  constructor() { super(); }
  speak() { super.speak(); }
}

interface

//class interface
interface Person {
  sayHello(message: string): void;
}

class Adult implements Person {
  sayHello(message: string): void {
    console.log(`Hello ${message}`);
  }
}

//fonction interface
interface SayHello {
  (message: string): string;
}

let sayHello: SayHello;

sayHello = function(source: string): string {
  return source.toLowerCase();
}

//parameter (object) interface
interface Message {
  message: string
  title?: string
}

function sayHello(options: Message) {
  console.log(`Hello ${options.message}`);
}

Et en JS ?

//class interface
class Person {
  constructor(){
    if(sayHello == undefined){
      throw new TypeDefError("sayHello is not implemented");
    }
  }
}

class Adult extends Person {
  this.sayHello(message) {
    console.log(`Hello ${message}`);
  }
}

Generics

Generics

//on function
function identity<T>(arg: T): T {
  return arg;
}

identity(5).toFixed(2); //-> '5.00'
identity(true); //-> true
identity('hello').toFixed(2); // compilation error : 
// Property 'toFixed' does not exist on type '"hello"'.

//on class
class Log<T> {
  log(value: T) {
    console.log(value);
  }
}

const numericLog = new Log<number>();
numericLog.log(5); //-> 5
numericLog.log('hello'); // compilation error
// Argument of type '"hello"' is not assignable to parameter of type 'number'.

Generics

//on interface
interface transform<T, U> {
  transform : (value:T) => U;
}

class NumberToStringTransform implements transform<number, string> {
  transform(value: number): string {
    return value.toString();
  }
}

const numberTransform = new NumberToStringTransform();
numberTransform.transform(3).toLowerCase(); //-> '3'
numberTransform.transform(3).toFixed(2); // compilation error
// Property 'toFixed' does not exist on type 'string'.

Merci !

&

Question ?

Loïc Mathieu -        @loicmathieu

TypeScript en 20 mn

By loicmathieu

TypeScript en 20 mn

  • 604