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
140
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
230
Componentes: DD
serabe
0
370
Introducción a JSONAPI
serabe
1
190
Bienvenidos a Ember Madrid
serabe
2
220
Lo que la cafeína le hizo a JS
serabe
1
230
Lo que la cafeína le hizo a JS
serabe
1
3k
Taller de Introducción a Ember.JS
serabe
1
200
Generadores en JavaScript
serabe
1
520
El diablo está en los detalles
serabe
0
660
Other Decks in Programming
See All in Programming
Spinner 軸ズレ現象を調べたらレンダリング深淵に飲まれた #レバテックMeetup
bengo4com
1
210
LLM Çağında Backend Olmak: 10 Milyon Prompt'u Milisaniyede Sorgulamak
selcukusta
0
140
GoLab2025 Recap
kuro_kurorrr
0
790
実はマルチモーダルだった。ブラウザの組み込みAI🧠でWebの未来を感じてみよう #jsfes #gemini
n0bisuke2
3
1.4k
ゲームの物理 剛体編
fadis
0
390
DevFest Android in Korea 2025 - 개발자 커뮤니티를 통해 얻는 가치
wisemuji
0
180
Flutter On-device AI로 완성하는 오프라인 앱, 박제창 @DevFest INCHEON 2025
itsmedreamwalker
1
170
The Art of Re-Architecture - Droidcon India 2025
siddroid
0
150
ThorVG Viewer In VS Code
nors
0
500
脳の「省エネモード」をデバッグする ~System 1(直感)と System 2(論理)の切り替え~
panda728
PRO
0
130
公共交通オープンデータ × モバイルUX 複雑な運行情報を 『直感』に変換する技術
tinykitten
PRO
0
180
ZJIT: The Ruby 4 JIT Compiler / Ruby Release 30th Anniversary Party
k0kubun
1
300
Featured
See All Featured
Principles of Awesome APIs and How to Build Them.
keavy
127
17k
The Pragmatic Product Professional
lauravandoore
37
7.1k
Digital Ethics as a Driver of Design Innovation
axbom
PRO
0
130
Save Time (by Creating Custom Rails Generators)
garrettdimon
PRO
32
1.9k
How to Ace a Technical Interview
jacobian
281
24k
[RailsConf 2023] Rails as a piece of cake
palkan
58
6.2k
Self-Hosted WebAssembly Runtime for Runtime-Neutral Checkpoint/Restore in Edge–Cloud Continuum
chikuwait
0
260
Art, The Web, and Tiny UX
lynnandtonic
304
21k
16th Malabo Montpellier Forum Presentation
akademiya2063
PRO
0
34
DevOps and Value Stream Thinking: Enabling flow, efficiency and business value
helenjbeal
1
75
Building Experiences: Design Systems, User Experience, and Full Site Editing
marktimemedia
0
350
Embracing the Ebb and Flow
colly
88
4.9k
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