Di materi JavaScript kamu sudah bikin class: cetakan object, dengan constructor yang menyimpan data lewat this dan method yang membacanya. TypeScript menambahkan dua hal: tipe untuk tiap property, dan penanda akses (access modifier) yang menentukan dari mana sebuah property boleh dipakai. Bayangin kantor: ruang tamu terbuka buat siapa saja, pintu arsip ditempeli tulisan "Khusus karyawan", dan brankas dikunci beneran. Tulisan di pintu cuma ampuh selama ada satpam yang menegur, dan satpamnya adalah TypeScript waktu memeriksa kodemu.
🧪 Tebakan cepat:
suaradi classHewanditandaiprivate, lalu di luar class kamu menulisconsole.log(kucing.suara). TypeScript memberi error. Kalau JavaScript hasil kompilasinya tetap dijalankan, apa yang tercetak: error,undefined, atauMeow? Tebak dulu, jawabannya ada di bagian "private cuma ada waktu dicek".
Property bertipe dan penanda akses
class Hewan {
public nama: string
private suara: string
constructor(nama: string, suara: string) {
this.nama = nama
this.suara = suara
}
bersuara(): string {
return this.nama + " bersuara: " + this.suara
}
}
public nama: stringdanprivate suara: stringmendeklarasikan property di atas class, lengkap dengan tipenya. Di TypeScript property wajib dideklarasikan dulu:this.nama = namatanpa deklarasi itu errorProperty 'nama' does not exist on type 'Hewan'.ts(2339).- Penanda akses ada tiga:
public(boleh dari mana saja, ini bawaannya kalau gak ditulis apa-apa),private(cuma di dalam class ini), danprotected(di class ini dan subclass-nya). Ada satu penanda lagi,readonly: boleh dibaca dari mana saja, tapi cuma boleh diisi waktu deklarasi atau diconstructor. bersuara(): stringartinya method ini mengembalikanstring:new Hewan("Kucing", "Meow").bersuara()hasilnya"Kucing bersuara: Meow".
Siapa boleh menyentuh apa
Sekarang ada subclass Kucing, lalu kode di luar class yang membaca dan mengganti suara:
class Kucing extends Hewan {
pamer(): string {
return "Suaraku " + this.suara
}
}
const kucing = new Kucing("Kucing", "Meow")
console.log(kucing.bersuara())
console.log(kucing.pamer())
console.log(kucing.suara)
kucing.suara = "Guk"
console.log(kucing.bersuara())
Ganti penanda di depan suara, dan TypeScript menilai tiap baris yang menyentuhnya:
Baris yang menyentuh suara |
public |
private |
protected |
readonly |
|---|---|---|---|---|
di dalam Hewan, method bersuara |
boleh | boleh | boleh | boleh |
di subclass Kucing, method pamer |
boleh | ts(2341) | boleh | boleh |
di luar, baca kucing.suara |
boleh | ts(2341) | ts(2445) | boleh |
di luar, ganti kucing.suara = "Guk" |
boleh | ts(2341) | ts(2445) | ts(2540) |
- ts(2341):
Property 'suara' is private and only accessible within class 'Hewan'.Subclass pun gak boleh. - ts(2445):
Property 'suara' is protected and only accessible within class 'Hewan' and its subclasses. - ts(2540):
Cannot assign to 'suara' because it is a read-only property.
Parameter properties: deklarasi dan isi sekaligus
Menulis suara tiga kali (deklarasi, parameter, this.suara = suara) itu capek. Jalan pintasnya: taruh penanda akses langsung di parameter constructor.
class Hewan {
constructor(public nama: string, private suara: string) {}
bersuara(): string {
return this.nama + " bersuara: " + this.suara
}
}
public nama: stringdi dalam kurungconstructorsekaligus mendeklarasikan propertynamadan mengisinya dengan argumen pertama, jadi badanconstructor-nya boleh kosong,{}. Ini disebut parameter property, dan class ini sama persis dengan versi panjang tadi.- Penandanya wajib:
public,private,protected, ataureadonly. Parameter tanpa penanda tetap parameter biasa, gak jadi property.
Sejak TypeScript 5.8 ada opsi erasableSyntaxOnly, untuk proyek yang menjalankan .ts cuma dengan menghapus tipenya (misalnya Node.js yang menjalankan file .ts langsung). Parameter property butuh kode tambahan di JavaScript (this.nama = nama), jadi kalau opsi itu nyala, dia ditolak: This syntax is not allowed when 'erasableSyntaxOnly' is enabled. ts(1294). Di proyek seperti itu, pakai versi panjang.
private cuma ada waktu dicek
Tipe dan penanda akses cuma dipakai waktu TypeScript memeriksa kode. Waktu tsc mengubahnya jadi JavaScript, semuanya dihapus. Versi panjang maupun parameter property jadi JS yang sama:
class Hewan {
nama;
suara;
constructor(nama, suara) {
this.nama = nama;
this.suara = suara;
}
// bersuara() tetap ada, tanpa ": string"
}
Kata private hilang, suara jadi property biasa. Jadi program Kucing tadi, kalau JS-nya tetap dijalankan walau ada error, mencetak Kucing bersuara: Meow, Suaraku Meow, Meow, lalu Kucing bersuara: Guk. kucing.suara mencetak Meow, dan gantinya ke Guk juga berhasil. Itu jawaban tebakannya. private itu tulisan "Khusus karyawan": TypeScript menegur di editor, tapi JavaScript-nya gak mengunci apa pun.
Butuh kunci beneran? Pakai private field bawaan JavaScript, yang diawali #:
class Hewan {
#suara: string
constructor(public nama: string, suara: string) {
this.#suara = suara
}
}
#suaratetap ada di JavaScript hasil kompilasi, dan JavaScript sendiri yang menjaganya.- Dari luar class (subclass juga), TypeScript menolak
kucing.#suara:Property '#suara' is not accessible outside class 'Hewan' because it has a private identifier.ts(18013). Kalau JS-nya tetap dijalankan, filenya gak jalan sama sekali:SyntaxError: Private field '#suara' must be declared in an enclosing class. #gak bisa dipakai di parameter property, jadi deklarasikan di atas lalu isi diconstructor.
implements dan abstract class
implements adalah janji bahwa class memenuhi bentuk sebuah interface (dari materi Interface). Kalau class Robot implements BisaBersuara lupa menulis method bersuara() yang diminta interface-nya, TypeScript menolak: Class 'Robot' incorrectly implements interface 'BisaBersuara'. ts(2420).
abstract class adalah class yang cuma boleh jadi induk. Dia boleh punya method abstract: method tanpa isi yang wajib ditulis oleh tiap subclass.
abstract class Hewan {
constructor(public nama: string) {}
abstract bersuara(): string
}
class Kucing extends Hewan {
bersuara(): string { return "Meow" }
}
new Kucing("Kucing").bersuara() // "Meow"
new Hewan("Siapa") // error ts(2511)
new Hewan(...)ditolak:Cannot create an instance of an abstract class.ts(2511).- Subclass yang lupa menulis
bersuara, misalnyaclass Ikan extends Hewan {}, juga ditolak:Non-abstract class 'Ikan' does not implement inherited abstract member bersuara from class 'Hewan'.ts(2515). - Sama seperti
private, kataabstractdanimplementsdihapus di JavaScript. Penjaganya cuma TypeScript.
⚠️ Jebakan yang sering ketemu
- Parameter tanpa penanda.
constructor(public nama: string, suara: string) {}cuma bikin propertynama.this.suarajadi errorProperty 'suara' does not exist on type 'Hewan'.ts(2339), dan di JavaScript nilainyaundefined: kalimatnya keluarKucing bersuara: undefined. - Deklarasi tanpa isi.
private suara: stringditulis di atas, tapithis.suara = suaralupa:Property 'suara' has no initializer and is not definitely assigned in the constructor.ts(2564). - Membaca
suaradari luar class di latihan. Latihannya menjalankan pemeriksa TypeScript dulu (modestrict, sepertitsc --noEmit), jadiconsole.log(kucing.suara)di luar class langsung gagal denganerror TS2341. Kalimatnya juga harus persisKucing bersuara: Meow, termasuk spasi dan titik dua.
TL;DR: Di class TypeScript, property dideklarasikan dengan tipenya. public boleh dari mana saja (bawaan), private cuma di dalam class itu, protected di class itu dan subclass-nya, readonly boleh dibaca tapi cuma diisi di deklarasi atau constructor. Parameter property, constructor(public nama: string, private suara: string) {}, mendeklarasikan dan mengisi sekaligus, asal ada penandanya (dan ditolak kalau erasableSyntaxOnly nyala). Semua penanda itu cuma dicek TypeScript dan hilang di JavaScript; kunci yang tetap ada waktu program jalan adalah #field. implements menjanjikan bentuk interface, abstract class gak bisa di-new dan memaksa subclass menulis method abstract-nya.