Nicole Oliver
Angular Engineer at Nrwl
      @nixallover

Component decorator

import { Component } from '@angular/core';

@Component({
 selector: 'my-app',
 templateUrl: './app.component.html',
 styleUrls: [ './app.component.css' ]
})
export class AppComponent  {}

Interesting uses

  • Configure property descriptors

  • Apply useful Lodash utilities

  • Enforce a required parameter

Log a method

class Planet {
  constructor(public name: string) {}

  @logMethod
  greet(greeting: string, isLoud: boolean = false) {
    const phrase = `${greeting} ${this.name}!`;
    console.log(isLoud ? phrase.toUpperCase(): phrase);
  }
}

const mars = new Planet('Mars');

mars.greet('Welcome to', true);

How will we use it?

Calling Planet.greet with {"0":"Welcome to","1":true}
WELCOME TO MARS!
Output

Log a method

function logMethod(
  target: Object, 
  key: string, 
  descriptor: PropertyDescriptor
) {
  const original = descriptor.value;

  descriptor.value = function() {
    const targetName = target.constructor.name;
    const args = JSON.stringify(arguments);
    console.log(`Calling ${targetName}.${key} with ${args}`);
    const result = original.apply(this, arguments);
    return result;
  }

  return descriptor;
}

Decorator definition

function logMethod(
  target: Object, 
  key: string, 
  descriptor: PropertyDescriptor
) {
  const original = descriptor.value;

  descriptor.value = function() {
    const targetName = target.constructor.name;
    const args = JSON.stringify(arguments);
    console.log(`Calling ${targetName}.${key} with ${args}`);
    const result = original.apply(this, arguments);
    return result;
  }

  return descriptor;
}

A way to observe, modify, and replace class declarations and members

classes, properties, methods, accessors, parameters

A way to provide annotations and a meta-programming syntax for class declarations and members

So what are TypeScript decorators?

Pattern    vs    Feature

Add behavior to an individual object, dynamically, without affecting the behavior of other objects from the same class

Add functionality to classes and class members at definition time

Are TypeScript decorators the same as ECMAScript decorators?

PropertyDescriptor
configurable
enumerable
writable
value
let cub = {};

cub.name = 'Rupert';

// Defaults - created by assignment
{ 
    configurable: true, 
    enumerable: true, 
    writable: true,
    value: 'Rupert'
}

Object.defineProperty(cub, 'name', {value: 'Rupert'});

// Defaults - created with Object.defineProperty
{ 
    configurable: false, 
    enumerable: false, 
    writable: false,
    value: 'Rupert'
}
function readonly(
  target: Object, 
  key: string, 
  descriptor: PropertyDescriptor
) {
  descriptor.writable = false;
  return descriptor;
}

Example: Read-Only Decorator

Defining our decorator

class Moon {
  constructor(public radius: number) {}

  @readonly
  circumference() {
    return 2 * Math.PI * this.radius;
  }
}

const moon = new Moon(60268);

moon.circumference = () => 100;
TypeError: Cannot assign to read only property 'circumference' of object '#<Moon>'
    at Object.<anonymous> (C:\Dev\space-project\moon.js:31:20)
    at Module._compile (module.js:635:30)
    at Object.Module._extensions..js (module.js:646:10)
    at Module.load (module.js:554:32)
    ...

output

Example: Read-Only Decorator

Applying our decorator

function enumerable(value: boolean) {
  return function(
    target: Object, 
    key: string, 
    descriptor: PropertyDescriptor
  ) {
    descriptor.enumerable = value;
    return descriptor;
  };
}

Example: Enumerable Decorator

Defining our decorator

class Moon {
  constructor(public radius: number) {}

  @enumerable(true)
  circumference() {
    return 2 * Math.PI * this.radius;
  }
}

const moon = new Moon(60268);

for (const key in moon) {
  console.log(`${key}: ${moon[key]}`);
}
radius: 60268
circumference: circumference() {
    return 2 * 3.14159265359 * this.radius;
}

output

Example: Enumerable Decorator

Applying our decorator

Resources & further reading

More on decorators in Angular

Get your free account for Nrwl's new developer empowerment platform

  • Online courses

  • Angular books

  • Videos & tutorials

  • Content recommendations

  • Cookbook recipes

  • Live broadcasts

connect.nrwl.io/ng-conf

Credits

Thanks!

Nicole Oliver

      @nixallover

Many thanks to
the ngConf organizers,

Valerie Kittel, Angular Seattle,
and my Nrwl colleagues
for their ideas and support!

Wrapping it up with decorators - ngConf 2019

By Nicole Oliver

Wrapping it up with decorators - ngConf 2019

As Angular developers we use decorators every day. Let's peek at how the core Angular decorators bring our code to life, and use that as a springboard for a discussion about creating our own magical wrappers in TypeScript.

  • 348
Loading comments...

More from Nicole Oliver