Masukkan Password
72 What is a Decorator
Kita masuk ke materi Decorators di TypeScript. Materi ini memang sedikit lebih “abstrak” dibanding interface, generic, atau class, jadi saya akan membangunnya pelan-pelan dari konsep paling dasar, lalu kita lihat apa yang sebenarnya terjadi ketika decorator digunakan.
Lecture ini memperkenalkan decorator sebagai fitur sintaks TypeScript yang bisa digunakan untuk menambahkan functionality atau memodifikasi behavior pada class, method, property, dan parameter. Poin utama lecture: decorator pada dasarnya adalah function yang diterapkan menggunakan simbol @.
1. Apa itu Decorator?
Secara sederhana:
Decorator adalah function yang ditempelkan pada sesuatu untuk memberikan behavior tambahan atau memodifikasi behavior-nya.
Misalnya kita punya:
class User {
name = "John";
age = 28;
}
Kita bisa menambahkan decorator:
@logger
class User {
name = "John";
age = 28;
}
Di sini:
@logger
adalah decorator.
Dan:
logger
adalah sebuah function.
Jadi jangan langsung menganggap @logger sebagai sesuatu yang misterius.
Secara konsep:
Decorator
↓
sebuah function
↓
ditempelkan ke class/method/property/etc.
↓
TypeScript menjalankan decorator tersebut
2. Analogi sederhana
Bayangkan kamu punya sebuah rumah:
🏠 Rumah
Rumah tersebut sudah bisa digunakan.
Kemudian kamu menambahkan:
🔒 CCTV
CCTV bukan rumahnya.
Tetapi CCTV memberikan kemampuan tambahan kepada rumah.
Atau:
🏠 Rumah
+
🔔 Doorbell
Decorator kira-kira seperti “lapisan tambahan” yang kita pasangkan ke sesuatu.
Decorator
↓
[Class]
↓
behavior tambahan
Jadi:
Decorator tidak harus menggantikan sesuatu. Ia bisa digunakan untuk menambahkan atau memodifikasi behavior.
3. Decorator bukan class khusus
Ini penting.
Decorator:
@logger
bukan:
class Logger {}
Dalam lecture, logger dibuat sebagai:
function logger(target: Function) {
console.log("logging");
}
Jadi:
logger
↓
FUNCTION
Inilah poin pertama yang harus kamu ingat:
Decorator pada dasarnya adalah function.
4. Membuat class User
Lecture mulai dengan class sederhana:
class User {
name: string = "John";
age: number = 28;
constructor() {
console.log("User class Constructor called");
}
}
Ada:
name: string = "John";
dan:
age: number = 28;
Kemudian constructor:
constructor() {
console.log("User class Constructor called");
}
5. Apa yang terjadi ketika membuat object?
Misalnya:
const user = new User();
Kata kuncinya adalah:
new User()
Ketika ini dijalankan, constructor akan dipanggil.
Jadi:
new User()
↓
constructor()
↓
console.log()
Output:
User class Constructor called
Lecture menggunakan contoh ini sebagai baseline sebelum decorator ditambahkan.
6. Sekarang kita buat decorator
Kita buat:
function logger(target: Function) {
console.log("logging");
}
Perhatikan:
function logger(...)
Ini function biasa.
Belum menjadi decorator sampai kita menggunakannya pada declaration dengan:
@logger
7. Cara memasang decorator ke class
Misalnya:
@logger
class User {
name: string = "John";
age: number = 28;
constructor() {
console.log("User class Constructor called");
}
}
Perhatikan posisi:
@logger
class User
Decorator berada tepat sebelum declaration yang ingin dihias/dekorasi.
Lecture menjelaskan bahwa decorator digunakan menggunakan simbol @ sebelum declaration yang ingin diberi decorator.
8. Jangan menulis @logger()
Ini penting untuk contoh decorator sederhana lecture.
Kita menulis:
@logger
bukan:
@logger()
Kenapa?
Karena:
logger
adalah function decorator yang akan digunakan oleh TypeScript.
Kalau:
logger()
itu berarti kita memanggil function secara langsung.
Untuk decorator yang sedang dipelajari:
@logger
sudah cukup.
9. Apa yang terjadi ketika @logger dipasang?
Misalnya:
@logger
class User {
...
}
TypeScript akan menggunakan function:
logger
sebagai decorator untuk User.
Secara konsep:
@logger
class User
berarti:
"Gunakan logger sebagai decorator untuk User"
Kemudian decorator mendapatkan reference terhadap class tersebut.
10. Apa itu target?
Function decorator:
function logger(target: Function) {
console.log("logging");
}
menerima parameter:
target
Lecture menjelaskan bahwa target dalam contoh ini akan merujuk pada User class.
Jadi secara konsep:
@logger
class User
│
│
▼
target
Artinya:
target === User
secara konsep.
11. Kenapa target tipenya Function?
Ini bagian yang mungkin membingungkan.
Kita menulis:
target: Function
Kenapa bukan:
target: User
?
Karena decorator class menerima reference terhadap class constructor, bukan instance User.
Lecture menjelaskan bahwa class JavaScript di balik layar menggunakan constructor function, sehingga class tersebut diperlakukan sebagai function pada konteks ini.
Untuk sekarang, cara paling mudah memahaminya:
User
↓
class constructor
↓
target
Sedangkan:
const user = new User();
adalah instance dari class tersebut.
Jadi bedakan:
User
↓
class / constructor
new User()
↓
instance / object
Decorator class bekerja pada bagian:
User
bukan object:
new User()
12. Hal yang sangat penting: decorator dijalankan sebelum constructor
Misalnya:
function logger(target: Function) {
console.log("logging");
}
@logger
class User {
constructor() {
console.log("User class Constructor called");
}
}
Kemudian:
const user = new User();
Output konsepnya:
logging
User class Constructor called
Kenapa?
Karena decorator diterapkan pada class declaration terlebih dahulu.
Baru ketika:
new User()
dijalankan, constructor dipanggil.
Jadi:
class User didefinisikan
↓
decorator dijalankan
↓
logger()
↓
logging
kemudian...
new User()
↓
constructor()
↓
User class Constructor called
Lecture menunjukkan urutan ini secara eksplisit.
13. Ini berbeda dengan constructor
Jangan sampai tertukar.
Constructor
class User {
constructor() {
console.log("constructor");
}
}
Constructor dipanggil ketika:
new User()
Jadi:
new User()
↓
constructor
Class decorator
@logger
class User {}
Decorator diterapkan ketika class declaration diproses.
Jadi secara konsep:
class declaration
↓
decorator
new User()
↓
constructor
14. Hal yang lebih menarik: tidak perlu membuat instance
Ini salah satu poin paling penting dari lecture.
Misalnya:
function logger(target: Function) {
console.log("logging");
}
@logger
class User {
constructor() {
console.log("constructor");
}
}
Dan kita tidak melakukan:
new User();
Apakah logger tetap dijalankan?
Menurut lecture: ya.
Karena decorator berkaitan dengan class declaration, bukan harus menunggu object dibuat.
Jadi:
@logger
class User
sudah cukup untuk membuat decorator dieksekusi.
15. Ini sering membingungkan pemula
Kita mungkin berpikir:
“Kalau constructor belum dipanggil, berarti decorator belum dipanggil.”
Tidak.
Keduanya berbeda.
Decorator
→ berkaitan dengan declaration
Constructor
→ berkaitan dengan instance creation
Contohnya:
@logger
class User {
constructor() {
console.log("constructor");
}
}
Tanpa:
new User();
tetap ada:
logging
tetapi tidak ada:
constructor
16. target bisa kita lihat
Untuk membuktikan bahwa target memang reference ke class, lecture melakukan:
function logger(target: Function) {
console.log("logging");
console.log(target);
}
Kemudian output menunjukkan User class.
Artinya:
target
↓
User class
Lecture menggunakan ini untuk menunjukkan bahwa decorator menerima reference terhadap class yang didekorasi.
17. Visualisasi lengkap
Coba lihat diagram ini:
@logger
│
▼
┌───────────┐
│ User │
│ class │
└───────────┘
│
│
▼
logger()
│
▼
target
│
▼
User class
Kemudian kalau kita membuat object:
const user = new User();
baru:
new User()
│
▼
constructor()
│
▼
"User class Constructor called"
18. Jadi decorator itu seperti “hook”
Untuk pemahaman awal, kamu bisa menganggap decorator seperti hook.
Misalnya:
@logger
class User {}
seolah-olah kita mengatakan:
“Sebelum/ketika class ini diproses, jalankan logic
logger.”
Jadi:
Class
│
├── decorator → logic tambahan
│
└── class behavior
Ini adalah salah satu alasan decorator berguna untuk hal-hal seperti:
- logging
- authorization
- validation
- metadata
- dependency injection
- framework behavior
Namun, bagian-bagian tersebut belum dibahas oleh lecture ini. Lecture baru memperkenalkan decorator sederhana dan bagaimana decorator menerima target.
19. Mengapa harus mengaktifkan experimentalDecorators?
Lecture kemudian membuka:
tsconfig.json
dan mengaktifkan:
"experimentalDecorators": true
Tujuannya supaya konfigurasi TypeScript mengizinkan penggunaan decorator dengan syntax yang digunakan oleh lecture.
Secara sederhana:
TypeScript
│
▼
Decorator syntax
│
▼
tsconfig.json
│
▼
experimentalDecorators
Jadi kalau decorator kamu error, salah satu hal yang perlu diperiksa adalah konfigurasi compiler yang digunakan project.
20. Apa sebenarnya yang dilakukan @?
Simbol:
@
adalah syntax khusus untuk decorator.
Contoh:
@logger
class User {}
Bacanya:
“
Userclass diberi decoratorlogger.”
Jangan membaca:
@logger
sebagai:
“panggil logger sekarang.”
Lebih tepat:
“Gunakan
loggersebagai decorator pada declaration ini.”
21. Decorator bisa digunakan pada beberapa hal
Lecture menyebut bahwa decorator dapat diterapkan pada:
Class
Method
Property
Parameter
Secara konsep:
Class
@logger
class User {}
Method
Konsepnya:
class User {
@logger
login() {}
}
Property
class User {
@logger
name = "John";
}
Parameter
class User {
login(@logger username: string) {}
}
Catatan: detail parameter decorator, method decorator, property decorator, dan perbedaan signature-nya belum dibahas dalam lecture ini. Jadi untuk sekarang fokus dulu pada class decorator.
22. Decorator vs function biasa
Ini penting.
Misalnya:
function logger() {
console.log("logging");
}
Kalau function biasa:
logger();
kita sendiri yang menentukan kapan function dipanggil.
Tetapi decorator:
@logger
class User {}
TypeScript/compiler/runtime decorator mechanism yang menyebabkan function decorator tersebut dijalankan sesuai aturan decorator.
Jadi secara mental:
Function biasa:
kita → logger()
Decorator:
kita → @logger
↓
TypeScript
↓
logger()
Lecture menekankan bahwa kita tidak perlu secara eksplisit memanggil function decorator.
23. Perbedaan logger dan logger()
Ini harus benar-benar jelas.
Function sebagai decorator
@logger
class User {}
Kita memberikan function:
logger
sebagai decorator.
Function dipanggil
logger();
Ini berarti kita sendiri memanggil function tersebut.
@logger()
Ini merupakan pola decorator factory, yang akan dibahas di lecture berikutnya.
Konsepnya berbeda karena:
@logger()
berarti kita menjalankan sesuatu terlebih dahulu untuk menghasilkan decorator.
Lecture berikutnya memang akan membahas cara membuat decorator yang menerima data dari luar.
Jadi untuk sekarang jangan dicampur dulu.
24. Decorator sederhana vs decorator dengan parameter
Lecture ini:
@logger
class User {}
Decorator langsung berupa function.
Sedangkan lecture berikutnya akan menuju pola seperti:
@logger("USER")
class User {}
Di sini:
"USER"
adalah data dari luar.
Konsepnya kira-kira:
logger("USER")
↓
menghasilkan decorator
↓
diterapkan ke User
Ini biasa disebut decorator factory.
Tapi untuk lecture sekarang cukup pahami bahwa:
@logger
dan:
@logger(...)
bisa mempunyai pola penggunaan yang berbeda.
25. Apa arti target secara sederhana?
Untuk class decorator, gunakan mental model:
function logger(target: Function) {
...
}
target adalah:
reference ke class yang sedang diberi decorator.
Misalnya:
@logger
class User {}
maka secara konsep:
target → User
Kalau:
@logger
class Product {}
maka:
target → Product
Jadi function yang sama:
logger
bisa digunakan untuk berbagai class.
26. Contoh dua class
Misalnya:
function logger(target: Function) {
console.log(target);
}
@logger
class User {}
@logger
class Product {}
Secara konsep:
User
↓
logger(User)
Product
↓
logger(Product)
Artinya decorator bisa mendapatkan informasi tentang declaration yang sedang didekorasi melalui parameter yang diberikan kepadanya.
27. Decorator tidak sama dengan inheritance
Jangan menyamakan:
@logger
class User {}
dengan:
class User extends Person {}
extends:
inheritance/hubungan parent-child.
Decorator:
memberikan/mengubah behavior declaration melalui decorator mechanism.
Jadi:
extends → inheritance
@decorator → decoration
28. Decorator juga bukan new
Ini juga berbeda:
new User()
berarti:
buat instance.
Sedangkan:
@logger
class User {}
berarti:
terapkan decorator pada class declaration.
Jadi:
@logger
class User
tidak berarti:
new User()
29. Urutan kejadian yang perlu kamu pahami
Ini mungkin bagian terpenting dari seluruh lecture.
Misalnya:
function logger(target: Function) {
console.log("logging");
}
@logger
class User {
constructor() {
console.log("constructor");
}
}
Saat file/class diproses:
User class ditemukan
↓
@logger ditemukan
↓
logger dijalankan
↓
"logging"
Kemudian ketika:
new User();
dijalankan:
new User()
↓
constructor()
↓
"constructor"
Maka:
logging
constructor
30. Kenapa decorator disebut powerful?
Karena satu function bisa digunakan untuk menambahkan behavior ke banyak declaration.
Misalnya secara konsep:
@logger
class User {}
@logger
class Product {}
@logger
class Order {}
Daripada menulis logic logging secara manual di setiap class, kita bisa membuat satu decorator:
function logger(...) {
...
}
dan menggunakannya di banyak tempat.
Jadi decorator membantu kita membuat behavior yang reusable.
31. Hubungannya dengan konsep yang sudah kamu pelajari
Kalau kita hubungkan dengan materi TypeScript sebelumnya:
Function
Kamu sudah belajar:
function add(a: number, b: number): number {
return a + b;
}
Decorator juga menggunakan function.
Class
Kamu sudah belajar:
class User {}
Decorator dapat ditempelkan ke class:
@logger
class User {}
Type
Kita bisa memberi tipe pada parameter decorator:
target: Function
Runtime
Ini berbeda dari banyak fitur TypeScript seperti:
interface
type
generic
yang terutama membantu saat compile/development.
Lecture menjelaskan decorator sebagai fitur yang digunakan untuk menambahkan functionality atau memodifikasi behavior pada runtime.
32. Kenapa decorator terasa berbeda dari TypeScript sebelumnya?
Karena sebelumnya kamu banyak belajar tentang type system.
Misalnya:
interface User {
name: string;
}
atau:
type ID = string | number;
Itu membantu TypeScript memahami tipe.
Decorator lebih dekat ke behavior.
Contohnya:
@logger
class User {}
Decorator melakukan sesuatu terhadap declaration tersebut.
Jadi secara kasar:
TypeScript type system
→ "Data ini tipe apa?"
Decorator
→ "Behavior tambahan apa yang ingin kita pasangkan?"
33. Ringkasan konsep dengan diagram
DECORATOR
│
▼
function
│
│ @
▼
class/method/
property/etc.
│
▼
behavior tambahan
/ modification
Untuk class decorator:
@logger
class User {}
│
▼
logger(target)
│
▼
target = User class
Dan:
@logger
│
▼
logger dijalankan
│
▼
class User tersedia sebagai target
Sedangkan:
new User()
│
▼
constructor()
adalah proses berbeda.
34. Cheat sheet
| Syntax/Konsep | Arti |
|---|---|
function logger() | Function biasa |
@logger | Menggunakan logger sebagai decorator |
target | Reference ke declaration yang didekorasi |
target: Function | Dalam contoh class decorator, target adalah class constructor |
@logger class User | User diberi decorator logger |
new User() | Membuat instance User |
constructor() | Dipanggil ketika instance dibuat |
experimentalDecorators | Konfigurasi compiler untuk decorator syntax yang digunakan lecture |
@logger() | Pola decorator factory; materi berikutnya |
35. Tiga hal yang wajib kamu ingat
Kalau nanti ditanya:
Apa itu decorator di TypeScript?
Jawaban sederhananya:
Decorator adalah function yang dapat diterapkan pada class, method, property, atau parameter untuk menambahkan atau memodifikasi behavior.
Kalau ditanya:
Apa fungsi
@?
Jawab:
@digunakan untuk menerapkan sebuah decorator pada declaration.
Kalau ditanya:
Apa itu
targetpada class decorator?
Jawab:
targetadalah reference terhadap class yang sedang diberi decorator.
36. Mental model paling sederhana
Bayangkan:
function logger(target: Function) {
console.log("logging");
}
@logger
class User {}
Baca seperti ini:
Saya punya function:
logger
Saya punya class:
User
Saya ingin:
logger
↓
User
Maka:
@logger
class User
Kemudian TypeScript menjalankan mekanisme decorator dan memberikan class tersebut sebagai target.
@logger
class User
↓
logger(User)
Ini bukan cara literal untuk menjelaskan seluruh transformasi compiler/runtime, tetapi sangat bagus sebagai mental model awal.
Kesimpulan
Lecture ini baru memperkenalkan fondasi decorator, jadi jangan terburu-buru memikirkan hal-hal kompleks dulu.
Urutannya cukup pahami:
1. Decorator = function
↓
2. Dipasang menggunakan @
↓
3. Bisa ditempel ke class/method/property/parameter
↓
4. @logger class User
↓
5. logger dijalankan untuk declaration tersebut
↓
6. Class yang didekorasi diberikan sebagai target
↓
7. Decorator tidak perlu dipanggil manual
↓
8. Class decorator tidak menunggu new User()
Dan perbedaan paling penting:
@logger
class User {}
│
└── decorator → bekerja pada class declaration
new User()
│
└── constructor → membuat instance
Jadi kalau kamu melihat:
@logger
class User {
constructor() {
console.log("constructor");
}
}
ingat saja:
@loggeradalah “lapisan/function tambahan” pada classUser, sedangkanconstructoradalah logic yang dijalankan ketika kita membuat objectnew User().
Lecture berikutnya akan masuk ke bagian yang lebih menarik: bagaimana membuat decorator yang bisa menerima data dari luar, misalnya pola seperti @logger("some data").