Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Decorating JavaScript - source{d} edition
Search
Sergio Arbeo
June 24, 2017
Programming
1
120
Decorating JavaScript - source{d} edition
An introduction to Class and property decorators, Stage 2, proposal.
Sergio Arbeo
June 24, 2017
Tweet
Share
More Decks by Sergio Arbeo
See All by Sergio Arbeo
Testing sin Dogmas
serabe
0
220
Componentes: DD
serabe
0
330
Introducción a JSONAPI
serabe
1
160
Bienvenidos a Ember Madrid
serabe
2
210
Lo que la cafeína le hizo a JS
serabe
1
210
Lo que la cafeína le hizo a JS
serabe
1
3k
Taller de Introducción a Ember.JS
serabe
1
190
Generadores en JavaScript
serabe
1
510
El diablo está en los detalles
serabe
0
590
Other Decks in Programming
See All in Programming
OpenTelemetryで始めるベンダーフリーなobservability / Vendor-free observability starting with OpenTelemetry
seike460
0
140
ruby.wasmとWebSocketで遊ぼう!
lnit
0
120
データと事例で振り返るDevin導入の"リアル" / The Realities of Devin Reflected in Data and Case Studies
rkaga
3
2.8k
OpenTelemetry + LLM = OpenLLMetry!?
yunosukey
2
200
はじめてのPDFKit.pdf
shomakato
0
110
マイコンでもRustのtestがしたい/KernelVM Kansai 11
tnishinaga
1
950
AIコーディングエージェントを 「使いこなす」ための実践知と現在地 in ログラス / How to Use AI Coding Agent in Loglass
rkaga
4
1.5k
事業KPIを基に価値の解像度を上げる
nealle
0
160
ドメイン駆動設計とXPで支える子どもの未来 / Domain-Driven Design and XP Supporting Children's Future
nrslib
0
330
AWS Summit Hong Kong 2025: Reinventing Programming - How AI Transforms Our Enterprise Coding Approach
dwchiang
0
150
2025年のz-index設計を考える
tak_dcxi
13
5k
ビカム・ア・コパイロット
ymd65536
1
170
Featured
See All Featured
Fight the Zombie Pattern Library - RWD Summit 2016
marcelosomers
233
17k
Producing Creativity
orderedlist
PRO
344
40k
It's Worth the Effort
3n
184
28k
Making the Leap to Tech Lead
cromwellryan
133
9.3k
We Have a Design System, Now What?
morganepeng
52
7.6k
4 Signs Your Business is Dying
shpigford
183
22k
Being A Developer After 40
akosma
91
590k
A designer walks into a library…
pauljervisheath
205
24k
RailsConf & Balkan Ruby 2019: The Past, Present, and Future of Rails at GitHub
eileencodes
137
33k
Evolution of real-time – Irina Nazarova, EuRuKo, 2024
irinanazarova
8
720
Why Our Code Smells
bkeepers
PRO
336
57k
A Tale of Four Properties
chriscoyier
159
23k
Transcript
Decorating JavaScript Sergio Arbeo Serabe Serabe
History
History • Early work from March, 2015 • Stage 2
for 11 months • PR for babylon merged 2 days ago.
What is a decorator?
What is a decorator? New Syntax
What is a decorator? import Evented from 'evented'; import {
mixins, readOnly } from 'decorators'; @mixins(Evented) class AbbaSong { @readOnly artist = 'ABBA'; } export default AbbaSong;
What is a decorator? import Evented from 'evented'; import {
mixins, readOnly } from 'decorators'; @mixins(Evented) class AbbaSong { @readOnly artist = 'ABBA'; } export default AbbaSong;
What is a decorator? import Evented from 'evented'; import {
mixins, readOnly } from 'decorators'; @mixins(Evented) class AbbaSong { @readOnly artist = 'ABBA'; } export default AbbaSong;
Syntax Valid @foo @foo(…args) @foo.bar @foo.bar(…args) @foo.bar.baz @foo.bar.baz(…args)
Syntax Valid @foo @foo(…args) @foo.bar @foo.bar(…args) @foo.bar.baz @foo.bar.baz(…args) Invalid @foo[bar]
@foo[bar](…args) @foo(…args).bar @foo(…args).bar(…args) @foo.bar(…args).baz @foo.bar(…args).baz(…args)
How can I implement one?
How to implement one? ClassDecorator: (Constructor, ParentClass, MemberDescriptor[]) : void
How to implement one? MemberDecorator: (MemberDescriptor) : MemberDescriptor
Member Descriptor interface MemberDescriptor { kind: "Property”, key: string, isStatic:
boolean, descriptor: PropertyDescriptor, extras?: MemberDescriptor[], finisher?: (klass): void; }
Member Descriptor interface MemberDescriptor { kind: "Property”, key: string, isStatic:
boolean, descriptor: PropertyDescriptor, extras?: MemberDescriptor[], finisher?: (klass): void; }
Member Descriptor interface MemberDescriptor { kind: "Property”, key: string, isStatic:
boolean, descriptor: PropertyDescriptor, extras?: MemberDescriptor[], finisher?: (klass): void; }
Member Descriptor interface MemberDescriptor { kind: "Property”, key: string, isStatic:
boolean, descriptor: PropertyDescriptor, extras?: MemberDescriptor[], finisher?: (klass): void; }
Member Descriptor interface MemberDescriptor { kind: "Property”, key: string, isStatic:
boolean, descriptor: PropertyDescriptor, extras?: MemberDescriptor[], finisher?: (klass): void; }
Member Descriptor interface MemberDescriptor { kind: "Property”, key: string, isStatic:
boolean, descriptor: PropertyDescriptor, extras?: MemberDescriptor[], finisher?: (klass): void; }
Member Descriptor interface MemberDescriptor { kind: "Property”, key: string, isStatic:
boolean, descriptor: PropertyDescriptor, extras?: MemberDescriptor[], finisher?: (klass): void; }
Member Descriptor interface MemberDescriptor { kind: "Property”, key: string, isStatic:
boolean, descriptor: PropertyDescriptor, extras?: MemberDescriptor[], finisher?: (klass): void; }
Property Descriptor type PropertyDescriptor = DataDescriptor | AccessorDescriptor;
Property Descriptor interface DataDescriptor { configurable?: boolean; enumerable?: boolean; value?:
any; writable?: boolean; }
Property Descriptor interface DataDescriptor { configurable?: boolean; enumerable?: boolean; value?:
any; writable?: boolean; }
Property Descriptor interface DataDescriptor { configurable?: boolean; enumerable?: boolean; value?:
any; writable?: boolean; }
Property Descriptor interface DataDescriptor { configurable?: boolean; enumerable?: boolean; value?:
any; writable?: boolean; }
Property Descriptor interface DataDescriptor { configurable?: boolean; enumerable?: boolean; value?:
any; writable?: boolean; }
Property Descriptor interface DataDescriptor { configurable?: boolean; enumerable?: boolean; value?:
any; writable?: boolean; }
Property Descriptor interface DataDescriptor { configurable?: boolean; enumerable?: boolean; value?:
any; writable?: boolean; }
Property Descriptor interface AccessorDescriptor { configurable?: boolean; enumerable?: boolean; get?():
any; set?(v: any): void; }
Property Descriptor interface AccessorDescriptor { configurable?: boolean; enumerable?: boolean; get?():
any; set?(v: any): void; }
Property Descriptor interface AccessorDescriptor { configurable?: boolean; enumerable?: boolean; get?():
any; set?(v: any): void; }
Property Descriptor interface AccessorDescriptor { configurable?: boolean; enumerable?: boolean; get?():
any; set?(v: any): void; }
Property Descriptor interface AccessorDescriptor { configurable?: boolean; enumerable?: boolean; get?():
any; set?(v: any): void; }
Property Descriptor type PropertyDescriptor = DataDescriptor | AccessorDescriptor;
How can I implement one?
Simple validator function validator(predicate) { return function(memberDescriptor) { let {
descriptor } = memberDescriptor; if ('writable' in descriptor) { decorateData(descriptor, predicate); } else { decorateAccessor(descriptor, predicate); } return memberDescriptor; }; };
Simple validator function validator(predicate) { return function(memberDescriptor) { let {
descriptor } = memberDescriptor; if ('writable' in descriptor) { decorateData(descriptor, predicate); } else { decorateAccessor(descriptor, predicate); } return memberDescriptor; }; };
Simple validator function validator(predicate) { return function(memberDescriptor) { let {
descriptor } = memberDescriptor; if ('writable' in descriptor) { decorateData(descriptor, predicate); } else { decorateAccessor(descriptor, predicate); } return memberDescriptor; }; };
Simple validator function validator(predicate) { return function(memberDescriptor) { let {
descriptor } = memberDescriptor; if ('writable' in descriptor) { decorateData(descriptor, predicate); } else { decorateAccessor(descriptor, predicate); } return memberDescriptor; }; };
Simple validator function validator(predicate) { return function(memberDescriptor) { let {
descriptor } = memberDescriptor; if ('writable' in descriptor) { decorateData(descriptor, predicate); } else { decorateAccessor(descriptor, predicate); } return memberDescriptor; }; };
Simple validator function validator(predicate) { return function(memberDescriptor) { let {
descriptor } = memberDescriptor; if ('writable' in descriptor) { decorateData(descriptor, predicate); } else { decorateAccessor(descriptor, predicate); } return memberDescriptor; }; };
Simple validator function validator(predicate) { return function(memberDescriptor) { let {
descriptor } = memberDescriptor; if ('writable' in descriptor) { decorateData(descriptor, predicate); } else { decorateAccessor(descriptor, predicate); } return memberDescriptor; }; };
Simple validator function decorateData(descriptor, predicate) { let { value }
= descriptor; descriptor.get = () => value; descriptor.set = (newValue) => { if (predicate(newValue)) { value = newValue; } }; delete descriptor.writable; delete descriptor.value; }
Simple validator function decorateData(descriptor, predicate) { let { value }
= descriptor; descriptor.get = () => value; descriptor.set = (newValue) => { if (predicate(newValue)) { value = newValue; } }; delete descriptor.writable; delete descriptor.value; }
Simple validator function decorateData(descriptor, predicate) { let { value }
= descriptor; descriptor.get = () => value; descriptor.set = (newValue) => { if (predicate(newValue)) { value = newValue; } }; delete descriptor.writable; delete descriptor.value; }
Simple validator function decorateData(descriptor, predicate) { let { value }
= descriptor; descriptor.get = () => value; descriptor.set = (newValue) => { if (predicate(newValue)) { value = newValue; } }; delete descriptor.writable; delete descriptor.value; }
Simple validator function decorateData(descriptor, predicate) { let { value }
= descriptor; descriptor.get = () => value; descriptor.set = (newValue) => { if (predicate(newValue)) { value = newValue; } }; delete descriptor.writable; delete descriptor.value; }
Simple validator function decorateData(descriptor, predicate) { let { value }
= descriptor; descriptor.get = () => value; descriptor.set = (newValue) => { if (predicate(newValue)) { value = newValue; } }; delete descriptor.writable; delete descriptor.value; }
Simple validator function decorateData(descriptor, predicate) { let { value }
= descriptor; descriptor.get = () => value; descriptor.set = (newValue) => { if (predicate(newValue)) { value = newValue; } }; delete descriptor.writable; delete descriptor.value; }
Simple validator function decorateAccessor(descriptor, predicate) { let { set }
= descriptor; descriptor.set = (newValue) => { if (predicate(newValue)) { set(newValue); } }; }
Simple validator function decorateAccessor(descriptor, predicate) { let { set }
= descriptor; descriptor.set = (newValue) => { if (predicate(newValue)) { set(newValue); } }; }
Simple validator function decorateAccessor(descriptor, predicate) { let { set }
= descriptor; descriptor.set = (newValue) => { if (predicate(newValue)) { set(newValue); } }; }
Simple validator function decorateAccessor(descriptor, predicate) { let { set }
= descriptor; descriptor.set = (newValue) => { if (predicate(newValue)) { set(newValue); } }; }
Simple validator function decorateAccessor(descriptor, predicate) { let { set }
= descriptor; descriptor.set = (newValue) => { if (predicate(newValue)) { set(newValue); } }; }
Simple validator const isString = validator( value => typeof value
=== 'string’ ); class MyClass { @isString @validator(x => x !== '1234') password = ""; }
Gotchas
Evaluation / Execution
Simple validator const isString = validator( value => typeof value
=== 'string’ ); class MyClass { @isString @validator(x => x !== '1234') password = ""; }
Simple validator const isString = validator( value => typeof value
=== 'string’ ); class MyClass { @isString @validator(x => x !== '1234') password = ""; } Evaluation
Simple validator const isString = validator( value => typeof value
=== 'string’ ); class MyClass { @isString @validator(x => x !== '1234') password = ""; } Evaluation
Simple validator const isString = validator( value => typeof value
=== 'string’ ); class MyClass { @isString @validator(x => x !== '1234') password = ""; } Execution
Simple validator const isString = validator( value => typeof value
=== 'string’ ); class MyClass { @isString @validator(x => x !== '1234') password = ""; } Execution
Simple validator isString( validator(el => el === '1234')( passwordMemberDescriptor )
)
setters / getters
setters / getters class MyClass { @duplicate get hola() {
return 'hola'; } @map( x => x.toLowerCase() ) set hola(x) { send(x); } }
setters / getters class MyClass { @duplicateGetter @mapSetter( x =>
x.toLowerCase() ) get hola() { return 'hola'; } set hola(x) { send(x); } }
setters / getters class MyClass { get hola() { return
'hola'; } @duplicateGetter @mapSetter( x => x.toLowerCase() ) set hola(x) { send(x); } }
Cool Things that Can Be Done
Classics • Read Only properties • Validations • Computed Properties
• Memoized methods • Autobinding • Better Singleton Classes • Conversion setters and getters • Deprecate methods • Debounce • Throttle • Map returned value
Different express API @express('/posts') class Posts { @get index(req, res)
{ } @authorized @post create(req, res) { } @get(':id') show(req, res) { } }
@I18ned class Operations { @i18nMethod('operations.sum') static sum(...args) { return args.reduce((a,
b) => a+b, 0); } } Operations.sum(1, 2) // 3 Operations.suma(2, 3) // 5 Operations.batuketa(2, 3) // 5 I18ned API
Any questions? Sergio Arbeo Serabe Serabe
Thank you! Sergio Arbeo Serabe Serabe