Le Guide Angular | Marmicode
  • Le Guide Angular par Marmicode
  • Pourquoi Angular ?
  • ECMAScript 6+
    • Un Peu d'Histoire
    • Propriétés du Langage
    • "Single-Threaded" donc Asynchrone
    • Event Loop
    • Classes
    • Hoisting is Dead: var vs. let vs. const
    • this & "binding"
    • Arrow Functions
    • Template Strings
    • Syntactic Sugar
      • Spread
      • Destructuring
      • Rest
      • Object Literal Property Value Shorthand
    • Named Parameters
    • Compatibilité
  • TypeScript
    • Pourquoi TypeScript ?
    • De l'ECMAScript au TypeScript
    • Visibilité des Propriétés
    • Typing des Propriétés
    • Types
    • Interfaces
    • Inference
    • Duck Typing
    • Duck Typing Patterns
      • Compatibilité de Librairies
      • Entity Constructor
    • Décorateurs
      • Décorateurs de Propriété
      • Décorateurs de Classe
      • Décorateurs de Méthode & Paramètres
    • Quelques Liens
  • Tools
    • Clavier mécanique
    • Git
    • Command Line
    • NodeJS
    • NPM
    • Yarn
      • Pourquoi Yarn ?
      • Définition et Installation des Dépendances
      • Scripts
      • Mise à Jour et Automatisation
    • Chrome
    • IntelliJ / WebStorm / VSCode
      • Raccourcis clavier IntelliJ / WebStorm
    • Floobits
    • Angular CLI
    • StackBlitz
    • Compodoc
  • Angular
    • Bootstrap
    • Composants
      • Root Component
      • Template Interpolation
      • Property Binding
      • Class & Style Binding
      • Event Binding
      • *ngIf
      • *ngFor
      • L'approche MVC
      • Création de Composants
      • Exemple
    • Container vs. Presentational Components
    • Interaction entre Composants
      • Input
      • Output
      • Exemple
    • Change Detection
      • Les Approches Possibles
      • Fonctionnement de la Change Detection
      • Optimisation de la Change Detection
      • Immutabilité
      • Quelques Liens
    • Project Structure & Modules
      • Entry Point
      • Définition d'un Module
      • Root Module
      • Feature Module
      • Shared Module
      • Exemple
    • Dependency Injection
      • Qu'est-ce que la "Dependency Injection" ?
      • Injection d'un Service Angular
      • Services & Providers
      • Portée des Services
      • Tree-Shakable Services
      • Class vs Injection Token
      • Exemple
    • Callback Hell vs. Promise vs. Async / Await
      • Callback Hell
      • Promise
      • Async / Await
    • Observables
      • Reactive Programming
      • Promise vs Observable
      • Subscribe
      • Unsubscribe ⚠️
      • Création d'un Observable
      • Opérateurs
        • Définition d'un Opérateur
        • Lettable Operators vs Legacy Methods
        • map
        • filter
        • mergeMap & switchMap
        • shareReplay
        • buffer
        • debounceTime
        • distinctUntilChanged
        • retry
      • Quelques Liens
      • Talks
    • Http
      • Pourquoi HttpClient ?
      • Utilisation de HttpClient
      • Utilisation dans un Service
      • Gestion de la Subscription ⚠️
    • State Management
      • Quelques Liens
      • Talks
    • GraphQL
    • Formulaires
      • Template-driven Forms 🤢
      • Reactive Forms 👍
        • Avantages des "Reactive Forms"
        • La boite à outils des "Reactive Forms"
        • Validation
        • Observation des Changements
    • Directives
      • Attribute Directive
      • Structural Directive
    • Pipes
    • Routing
      • Mise en Place du Routing
      • Lazy Loading
      • Project Structure
      • Route Guards
    • Testing
      • Unit-Testing
        • 📺Introduction au Test-Driven Development
        • Jasmine
        • Unit-Test Synchrone
        • Test-Driven Development
        • Unit-Test Asynchrone
        • TestBed
        • Unit-Test d'un Service
        • Unit-Test d'un Composant
        • Unit-Test et Spies
        • Unit-Test et HttpClient
      • End-to-End
      • Talks
    • Sécurité
      • Quelques Liens
    • Animation
    • Internationalisation
    • Quelques Liens
  • Cookbook
    • Authentification et Autorisation
    • Remplacement Dynamique de Composants
    • Lazy Loading without Router
    • Project Structure
    • SCAM Modules
    • Setup a Mock ReSTful API
  • Autres Ressources
  • Stay Tuned
    • 🎁-20% sur nos workshops avec le code GUIDEANGULAR
    • 🐦Suivez-moi !
    • 📺Cours Vidéo
    • 📬Newsletter
    • 📝Blog
  • Nos Services
    • Formation Angular
    • Atelier Unit-Testing Angular
    • Atelier Architecture Angular
    • Consultation à Distance & Code Review
  • Nos Guides
    • Guide Agile
    • Guide API ReST
    • Guide NodeJS
Propulsé par GitBook
Sur cette page
  • Mémorisation des résultats
  • Contract checking en runtime
  1. TypeScript
  2. Décorateurs

Décorateurs de Méthode & Paramètres

Un décorateur de méthode permet d'en modifier le comportement par "wrapping".

Le décorateur en exemple ci-dessous n'opère aucun changement.

const Noop = () => (target, key: string) => {
    return target[key];
};

class Calculator {

    @Noop()
    sum(a, b) {
        console.log('computing...');
        return a + b;
    }

}

const calculator = new Calculator();

Remarquez le pattern de "currying" très fréquent dans l'implémentation de décorateurs.

La syntaxe suivante :

const Noop = () => {
    return (target, key) => {
        return target[key];
    };
}

... est identique à celle-ci :

const Noop = () => (target, key) => {
    return target[key];
};

A consommer avec modération.

Les décorateurs de paramètres permettent principalement d'ajouter des metadata à la classe pour que les décorateurs de méthode puissent s'en servir.

Mémorisation des résultats

Le décorateur ci-dessous construit progressivement un objet de mémorisation permettant de "mapper" les paramètres au dernier résultat obtenu afin d'éviter de refaire le même calcul inutilement.

const Memoize = () => (target, key: string) => {

    const memory = {};

    const original = target[key];

    target[key] = function (...args) {

        /* Retrieve last returned value from memory if available. */
        const value = memory[args.toString()];

        if (value !== undefined) {
            return value;
        }

        const result = original.apply(this, args);

        memory[args.toString()] = result;

        return result;

    };

};

class Calculator {

    @Memoize()
    sum(a, b) {
        console.log('computing...');
        return a + b;
    }

}

const calculator = new Calculator();

console.log(calculator.sum(1, 2));
// computing...
// 3
console.log(calculator.sum(1, 2));
// 3
console.log(calculator.sum(1, 2));
// 3
console.log(calculator.sum(2, 2));
// computing...
// 4
console.log(calculator.sum(1, 2));
// 3

Contract checking en runtime

import 'reflect-metadata';

const _contractDictMetadataKey = '__contractDict';

const ApplyContracts = () => (target, key: string) => {

    const originalMethod = target[key];
    const contractDict = Reflect.getOwnMetadata(_contractDictMetadataKey, target, key);

    target[key] = function (...argList) {

        if (contractDict !== undefined) {

            argList.forEach((value, index) => {

                const contract = contractDict[index];

                if (contract === undefined) {
                    return;
                }

                if (!contract(value)) {
                    throw new Error(`Value '${value}' does not respect contract for \`${target.constructor.name}.${key}(param_${index})\`.`);
                }

            });

        }

        return originalMethod(...argList);

    }

};

const Contract = (contract: (value: any) => boolean) => (target, key, index): any => {

    let contractDict = Reflect.getOwnMetadata(_contractDictMetadataKey, target, key);

    if (contractDict === undefined) {
        contractDict = {};
    }

    contractDict[index] = contract;

    Reflect.defineMetadata(_contractDictMetadataKey, contractDict, target, key);

};

const isPositive = value => value > 0;

class Utils {

    @ApplyContracts()
    double(@Contract(isPositive) number: number): number {
        return number * 2;
    }

}

console.log(new Utils().double(2)); // 4

// Error: Value '0' does not respect contract for `Utils.double(param_0)`.
console.log(new Utils().double(0));                
PrécédentDécorateurs de ClasseSuivantQuelques Liens

Dernière mise à jour il y a 7 ans