Nicole Oliver
I'm a software developer who loves teaching and learning! I also play with paint and pixels.
Nicole Oliver
Angular Engineer at Nrwl
@nixallover
import { Component } from '@angular/core';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent {}
Configure property descriptors
Apply useful Lodash utilities
Enforce a required parameter
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);
Calling Planet.greet with {"0":"Welcome to","1":true}
WELCOME TO MARS!
Output
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;
}
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
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
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;
}
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
Applying our decorator
function enumerable(value: boolean) {
return function(
target: Object,
key: string,
descriptor: PropertyDescriptor
) {
descriptor.enumerable = value;
return descriptor;
};
}
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
Applying our decorator
connect.nrwl.io/ng-conf
Nicole Oliver
@nixallover
Many thanks to
the ngConf organizers,
Valerie Kittel, Angular Seattle,
and my Nrwl colleagues
for their ideas and support!
By Nicole Oliver
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.
I'm a software developer who loves teaching and learning! I also play with paint and pixels.