Masukkan Password
44 Metode Getter & Setter
Lecture ini membahas getter, setter, dan computed properties di TypeScript. Konsepnya sebenarnya berasal dari JavaScript juga, tetapi TypeScript memberikan kita type checking sehingga penggunaannya lebih aman.
Kalau disederhanakan, inti besarnya adalah:
Getter digunakan untuk membaca property dengan cara yang terkontrol, sedangkan setter digunakan untuk mengubah property dengan cara yang terkontrol.
Dan dari getter kita juga bisa membuat computed property, yaitu property yang nilainya dihitung dari property lain.
1. Masalah yang ingin diselesaikan Getter & Setter
Kita mulai dari contoh sederhana.
Misalnya kita punya:
class Person {
public name: string;
private age: number | null = null;
constructor(name: string) {
this.name = name;
}
}
Kita punya:
public name
dan:
private age
Karena age adalah private, kita tidak bisa melakukan:
const person = new Person("John");
console.log(person.age);
TypeScript akan memberikan error:
Property 'age' is private
Kenapa?
Karena:
private age
hanya boleh digunakan di dalam class Person.
2. Kenapa tidak dibuat public saja?
Kita mungkin berpikir:
“Kalau saya ingin membaca age dari luar, tinggal ubah menjadi
public.”
Bisa.
Tapi ada masalah.
Kalau:
public age: number;
maka dari luar kita bisa melakukan:
person.age = -100;
Padahal umur:
-100 tahun
tidak masuk akal.
Atau kita bisa melakukan:
person.age = 9999;
Ini juga tidak masuk akal.
Jadi kita ingin sesuatu seperti:
Orang luar
│
├── boleh membaca age
│
└── boleh mengubah age
│
↓
TAPI...
│
↓
harus melewati aturan tertentu
Nah, getter dan setter sangat berguna untuk hal seperti ini.
3. Getter itu apa?
Getter adalah mekanisme untuk membaca nilai property melalui syntax seperti property biasa.
Contohnya:
class Person {
private age: number | null = null;
get age() {
return this.age;
}
}
Tapi ada satu masalah: kita tidak boleh punya:
private age
dan:
get age()
dengan nama yang sama secara langsung seperti itu, karena akan terjadi konflik/rekursi.
Biasanya kita menggunakan nama internal berbeda, misalnya:
class Person {
private _age: number | null = null;
get age() {
return this._age;
}
}
Perhatikan:
_age
adalah property internal.
Sedangkan:
age
adalah getter yang diekspos ke luar.
4. Kenapa menggunakan underscore _age?
Ini adalah konvensi penamaan, bukan aturan wajib TypeScript.
Kita sering melihat:
private _age
untuk menandakan:
“Ini adalah property internal yang sebenarnya menyimpan data.”
Sedangkan:
get age()
adalah interface yang digunakan dari luar.
Visualnya:
Person
┌─────────────────┐
│ private _age │
│ ↑ │
│ │ │
│ get age() │
└───────┬─────────┘
│
↓
person.age
5. Cara membuat Getter
Syntax-nya:
get namaProperty() {
return nilai;
}
Contoh:
class Person {
private _age: number | null = null;
get age() {
return this._age;
}
}
Kemudian:
const person = new Person();
console.log(person.age);
Yang menarik adalah kita tidak menulis ().
Bukan:
person.age();
Tetapi:
person.age;
6. Getter terlihat seperti property, bukan method
Walaupun syntax pembuatannya terlihat seperti method:
get age() {
return this._age;
}
ketika digunakan, kita memperlakukannya seperti property:
person.age;
Bukan:
person.age();
Ini salah:
person.age();
Kenapa?
Karena age adalah getter property.
7. Kenapa getter berguna?
Getter tidak hanya berguna untuk:
return this._age;
Kita juga bisa memasukkan logic di dalam getter.
Misalnya:
get age() {
if (this._age !== null) {
return this._age;
}
throw new Error(
`Age is not defined for person ${this.name}`
);
}
Sekarang kita punya kontrol.
Kalau:
_age = 60
maka:
person.age
menghasilkan:
60
Tetapi kalau:
_age = null
maka:
person.age
menghasilkan error:
Age is not defined for person John
8. Ini alasan penting menggunakan Getter
Tanpa getter, kalau property dibuat public:
public age: number | null;
orang luar bisa langsung mengambil:
person.age
tanpa ada kontrol.
Dengan getter:
get age() {
// validasi
// transformasi
// logic
// baru return value
}
kita bisa mengontrol apa yang terjadi ketika seseorang membaca property.
Jadi getter bisa dianggap sebagai:
“Pintu untuk membaca data internal.”
9. Analogi Getter
Bayangkan sebuah ATM.
Kamu ingin melihat saldo.
Kamu tidak masuk ke database bank dan mengambil:
database.balance
secara langsung.
Kamu meminta:
getBalance()
Bank kemudian bisa melakukan:
cek akun
↓
cek status
↓
ambil saldo
↓
tampilkan
Getter mirip dengan konsep ini.
Data internal:
_age
tidak langsung diberikan.
Kita menyediakan:
age
sebagai pintu untuk membacanya.
10. Sekarang Setter
Kalau getter digunakan untuk membaca, setter digunakan untuk mengubah/mengisi nilai.
Syntax:
set namaProperty(value: type) {
// logic
}
Contoh:
class Person {
private _age: number | null = null;
get age() {
return this._age;
}
set age(value: number) {
this._age = value;
}
}
Sekarang:
person.age = 90;
akan memanggil setter.
11. Ini bagian yang sangat penting
Ketika kita menulis:
person.age = 90;
sebenarnya TypeScript akan menggunakan:
set age(value: number) {
this._age = value;
}
Jadi secara konsep:
person.age = 90
↓
set age(90)
↓
this._age = 90
Kita tidak memanggil setter seperti method:
person.age(90); // ❌
Tetapi:
person.age = 90; // ✅
12. Getter + Setter
Sekarang kita punya:
class Person {
private _age: number | null = null;
get age() {
return this._age;
}
set age(value: number) {
this._age = value;
}
}
Penggunaannya:
const person = new Person();
person.age = 90;
console.log(person.age);
Alurnya:
person.age = 90
↓
setter dipanggil
↓
_age = 90
↓
person.age
↓
getter dipanggil
↓
return _age
↓
90
13. Setter bisa melakukan validasi
Nah, ini salah satu kegunaan terbesar setter.
Misalnya umur tidak boleh negatif.
Kita bisa melakukan:
set age(value: number) {
if (value >= 0) {
this._age = value;
} else {
throw new Error("Age cannot be a negative value");
}
}
Sekarang:
person.age = 90;
✅ valid.
Sedangkan:
person.age = -10;
❌ error.
14. Kenapa validasi sebaiknya di Setter?
Karena semua perubahan terhadap age akan melewati setter.
Misalnya:
person.age = 90;
→ setter
person.age = -10;
→ setter
person.age = 25;
→ setter
Jadi kita punya satu tempat untuk menjaga aturan.
Daripada setiap kali mengubah age harus menulis:
if (age >= 0) {
// ...
}
di banyak tempat.
15. Contoh lengkap Person
Sekarang kita bisa membuat versi yang lebih lengkap:
class Person {
public name: string;
private _age: number | null = null;
constructor(name: string) {
this.name = name;
}
get age() {
if (this._age !== null) {
return this._age;
}
throw new Error(
`Age is not defined for person ${this.name}`
);
}
set age(value: number) {
if (value >= 0) {
this._age = value;
} else {
throw new Error(
"Age cannot be a negative value"
);
}
}
}
Penggunaan:
const person = new Person("John");
person.age = 90;
console.log(person.age);
Output:
90
16. Bagaimana kalau age belum di-set?
Misalnya:
const person = new Person("John");
console.log(person.age);
Karena:
private _age: number | null = null;
maka getter menemukan:
this._age === null
dan melempar:
Age is not defined for person John
Ini contoh bahwa getter bisa mengandung logic.
17. Read-only, Read-write, dan Write-only
Lecture kemudian membahas hal yang menarik.
Getter dan setter menentukan apakah property bisa dibaca, ditulis, atau keduanya.
Hanya Getter
get age() {
return this._age;
}
Tidak ada setter.
Maka:
console.log(person.age);
✅ boleh.
Tetapi:
person.age = 90;
❌ tidak boleh.
Ini menjadi konsep:
read-only property
Secara sederhana:
read ✅
write ❌
18. Getter + Setter
Kalau kita punya keduanya:
get age() {
return this._age;
}
set age(value: number) {
this._age = value;
}
Maka:
person.age
✅ bisa membaca.
Dan:
person.age = 90;
✅ bisa mengubah.
Jadi:
read ✅
write ✅
Ini adalah read-write property.
19. Hanya Setter
Kalau hanya:
set age(value: number) {
this._age = value;
}
maka:
person.age = 90;
✅ bisa.
Tetapi:
console.log(person.age);
❌ tidak bisa membaca melalui getter karena getter tidak tersedia.
Ini disebut:
write-only property
Walaupun dalam praktik, write-only properties jauh lebih jarang digunakan dibanding getter atau getter+setter.
20. Ringkasan Getter/Setter
Getter saja
↓
Read-only
Setter saja
↓
Write-only
Getter + Setter
↓
Read + Write
Atau:
| Definisi | Baca | Tulis |
|---|---|---|
get saja | ✅ | ❌ |
set saja | ❌ | ✅ |
get + set | ✅ | ✅ |
21. Sekarang masuk ke Computed Property
Ini bagian kedua yang penting dari lecture.
Misalnya kita membuat class:
class Circle {
private radius: number;
}
Circle memiliki:
radius
Kemudian kita ingin mengetahui:
diameter
Rumusnya:
diameter = radius × 2
Kita sebenarnya tidak perlu menyimpan diameter sebagai property terpisah.
Kenapa?
Karena diameter bisa dihitung dari radius.
22. Computed Property itu apa?
Computed property adalah property yang nilainya diperoleh dari hasil perhitungan berdasarkan property/data lain.
Misalnya:
get diameter() {
return this.radius * 2;
}
Di sini kita tidak punya:
private diameter: number;
Tetapi kita punya:
get diameter()
yang menghitung diameter berdasarkan:
this.radius
Jadi:
radius = 10
↓
diameter = radius × 2
↓
diameter = 20
23. Contoh Circle
class Circle {
private radius: number;
constructor(radius: number) {
this.radius = radius;
}
get radiusValue() {
return this.radius;
}
set radiusValue(value: number) {
this.radius = value;
}
get diameter() {
return this.radius * 2;
}
}
Kemudian:
const circle = new Circle(10);
console.log(circle.diameter);
Hasil:
20
Perhatikan:
circle.diameter
bukan:
circle.diameter()
Karena diameter adalah getter.
24. Kenapa disebut “computed”?
Karena nilai diameter tidak disimpan secara langsung.
Yang disimpan:
radius = 10
Sedangkan diameter dihitung:
radius * 2
Jadi:
Circle
│
↓
radius = 10
│
↓
get diameter
│
↓
10 × 2 = 20
25. Keuntungan Computed Property
Misalnya radius berubah:
circle.radiusValue = 20;
Kemudian:
console.log(circle.diameter);
hasilnya otomatis:
40
Kita tidak perlu melakukan:
circle.diameter = 40;
karena diameter selalu dihitung dari radius.
Ini menghindari data yang tidak sinkron.
26. Masalah kalau diameter disimpan sebagai property biasa
Misalnya kita melakukan:
class Circle {
radius: number;
diameter: number;
}
Kemudian:
circle.radius = 10;
circle.diameter = 20;
Kemudian seseorang mengubah:
circle.radius = 50;
Sekarang:
radius = 50
diameter = 20 ❌
Data tidak sinkron.
Padahal seharusnya:
diameter = 100
Dengan computed property:
get diameter() {
return this.radius * 2;
}
tidak ada masalah tersebut.
Karena setiap kali kita membaca:
circle.diameter
TypeScript/JavaScript menghitung berdasarkan radius saat itu.
27. Computed Property dengan Setter
Lecture juga menunjukkan sesuatu yang sedikit lebih menarik.
Kita bisa membuat:
get diameter()
dan:
set diameter(value)
Misalnya:
class Circle {
private radius: number;
constructor(radius: number) {
this.radius = radius;
}
get diameter() {
return this.radius * 2;
}
set diameter(value: number) {
this.radius = value / 2;
}
}
Sekarang:
const circle = new Circle(10);
Maka:
console.log(circle.diameter);
hasil:
20
28. Apa yang terjadi ketika diameter diubah?
Misalnya:
circle.diameter = 40;
Kita tidak punya property diameter sebenarnya.
Yang terjadi:
circle.diameter = 40
↓
set diameter(40)
↓
radius = 40 / 2
↓
radius = 20
Jadi diameter sebenarnya hanya representasi lain dari radius.
29. Ini konsep yang sangat bagus
Perhatikan:
get diameter() {
return this.radius * 2;
}
set diameter(value: number) {
this.radius = value / 2;
}
Getter:
radius → diameter
Setter:
diameter → radius
Jadi kita bisa menggunakan dua cara untuk memanipulasi data yang sama.
radius
↙ ↘
↙ ↘
getter setter
↓ ↑
diameter ←──────┘
30. Full contoh Circle
Versi yang lebih rapi:
class Circle {
private _radius: number;
constructor(radius: number) {
this._radius = radius;
}
get radius() {
return this._radius;
}
set radius(value: number) {
if (value < 0) {
throw new Error(
"Radius cannot be negative"
);
}
this._radius = value;
}
get diameter() {
return this._radius * 2;
}
set diameter(value: number) {
if (value < 0) {
throw new Error(
"Diameter cannot be negative"
);
}
this._radius = value / 2;
}
}
Sekarang:
const circle = new Circle(10);
Kita bisa:
console.log(circle.radius);
Output:
10
Dan:
console.log(circle.diameter);
Output:
20
Kalau:
circle.radius = 25;
maka:
console.log(circle.diameter);
hasil:
50
Sebaliknya:
circle.diameter = 100;
maka radius menjadi:
50
31. Hal penting: Getter bukan berarti “mengubah private menjadi public”
Ini kesalahpahaman yang cukup umum.
Misalnya:
private _age: number;
kemudian:
get age() {
return this._age;
}
Bukan berarti:
“
_agesekarang menjadi public.”
Tidak.
Yang terjadi adalah kita membuat cara terkontrol untuk membaca _age.
Jadi:
private _age
│
│ tidak bisa diakses langsung
↓
get age()
│
│ akses terkontrol
↓
public-facing property
32. Getter/Setter dan Encapsulation
Konsep ini sangat erat dengan encapsulation.
Encapsulation berarti:
Menyembunyikan detail internal object dan memberikan akses melalui interface yang terkontrol.
Contohnya:
private _age
adalah detail internal.
Kemudian:
get age()
set age()
menjadi interface untuk berinteraksi dengan data tersebut.
Jadi:
Outside
│
│ age
↓
┌──────────────────────┐
│ Person │
│ │
│ private _age │
│ │
│ get age() │
│ set age(value) │
└──────────────────────┘
33. Kenapa tidak langsung menggunakan method?
Sebenarnya kita juga bisa membuat:
getAge() {
return this._age;
}
setAge(value: number) {
this._age = value;
}
Kemudian:
person.getAge();
person.setAge(90);
Ini valid.
Tetapi getter/setter memberikan syntax yang lebih natural:
person.age;
person.age = 90;
Jadi dari sisi pengguna object, age terlihat seperti property biasa, walaupun di belakang layar ada logic yang dijalankan.
34. Perbedaan Method biasa vs Getter/Setter
Method
getAge() {
return this._age;
}
Penggunaan:
person.getAge();
Ada ().
Getter
get age() {
return this._age;
}
Penggunaan:
person.age;
Tidak ada ().
Setter
set age(value: number) {
this._age = value;
}
Penggunaan:
person.age = 90;
Bukan:
person.age(90);
35. Satu mental model yang sangat berguna
Bayangkan getter dan setter sebagai pintu masuk dan pintu keluar data.
CLASS
┌─────────────────────┐
│ │
│ private _age │
│ │
│ ↑ ↓ │
│ │ │ │
│ getter setter │
│ │ │ │
└──────┼───────┼──────┘
│ │
↓ ↑
READ WRITE
Getter:
READ → ambil data
Setter:
WRITE → ubah data
Dan keduanya bisa punya validasi/logic.
36. Bedakan _age dan age
Ini juga penting.
Misalnya:
private _age: number | null = null;
dan:
get age() {
return this._age;
}
Maka:
_age
adalah data sebenarnya.
Sedangkan:
age
adalah interface/accessor.
Jadi:
person.age
sebenarnya mengakses:
get age()
yang kemudian membaca:
this._age
37. Kesimpulan besar lecture
Lecture ini sebenarnya mengajarkan 3 konsep yang saling berhubungan:
1. Getter
Untuk membaca property secara terkontrol.
get age() {
return this._age;
}
Digunakan:
person.age;
2. Setter
Untuk mengubah property secara terkontrol.
set age(value: number) {
this._age = value;
}
Digunakan:
person.age = 90;
Setter sangat berguna untuk validation:
set age(value: number) {
if (value < 0) {
throw new Error("Age cannot be negative");
}
this._age = value;
}
3. Computed Property
Property yang nilainya dihitung dari property lain.
get diameter() {
return this.radius * 2;
}
Jadi:
radius = 10
↓
diameter = 20
Tidak perlu menyimpan diameter secara terpisah.
🧠 Cheat sheet
| Konsep | Fungsi | Cara menggunakan |
|---|---|---|
private | Menyembunyikan data | this._age |
get | Membaca data | person.age |
set | Mengubah data | person.age = 90 |
| Getter saja | Read-only | Bisa baca, tidak bisa set |
| Setter saja | Write-only | Bisa set, tidak bisa baca |
| Getter + Setter | Read-write | Bisa baca & set |
| Computed property | Nilai hasil perhitungan | circle.diameter |
Dan mental model terakhir yang paling penting:
private data
│
┌──────────┴──────────┐
↓ ↓
GETTER SETTER
│ │
↓ ↓
membaca mengubah
│ │
└──────────┬──────────┘
↓
controlled access
Jadi jangan melihat getter/setter hanya sebagai syntax baru. Pahami alasan penggunaannya: kita ingin menyembunyikan data internal (private) sambil tetap menyediakan cara yang aman dan terkontrol untuk membaca, mengubah, atau menghitung data tersebut.