Menu

Access Modifier TypeScript: public, private, protected

TypeScript punya tiga access modifier, yaitu public, private, dan protected, ditambah readonly. Pelajari apa yang diizinkan masing-masing, kenapa private di TypeScript hanya diperiksa saat kompilasi sementara field #private JavaScript ditegakkan saat runtime, dan mana yang sebaiknya dipilih.

Halaman ini dilengkapi editor yang bisa dijalankan. Edit, jalankan, dan lihat output-nya seketika.

TypeScript punya tiga access modifier untuk member class: public (default), protected, dan private. Modifier ini mengatur di mana sebuah member boleh dipakai, dan compiler melaporkan setiap akses dari tempat yang salah.

Baris terakhir adalah error kompilasi, tetapi lihat apa yang tetap tercetak saat kode dijalankan: 123-45-6789. Itulah fakta terpenting di halaman ini, dan bagian private menjelaskannya.

Apa yang Diizinkan Setiap Modifier

ModifierDi dalam classDi subclassDari luarDitegakkan saat runtime
public (default)yayayatidak ada yang perlu ditegakkan
protectedyayatidaktidak
privateyatidaktidaktidak
#name (JavaScript)yatidaktidakya
readonlybaca, dan tulis di constructorbacabacatidak

Modifier ini berlaku untuk field, method, getter dan setter, constructor, serta parameter property (constructor(private id: string)). Menulis public bersifat opsional, dan banyak codebase tidak menuliskannya.

private Hanya Diperiksa Saat Kompilasi

TypeScript menghapus private bersama tipe lainnya. Class hasil kompilasi berisi property biasa, jadi apa pun yang tidak melewati pemeriksa tipe bisa melihatnya: pemanggil JavaScript biasa, JSON.stringify, Object.keys, bahkan notasi kurung siku milik TypeScript sendiri, yang sengaja diizinkan sebagai jalan pintas.

Itu tidak masalah untuk tujuan private yang sebenarnya: memberi tahu developer lain (dan editormu) bahwa sebuah member adalah detail implementasi. Ini bukan batas keamanan, dan field private akan ikut masuk ke log dan respons JSON kecuali kamu membuangnya sendiri.

Field #private: Ditegakkan Saat Runtime

JavaScript punya field private sendiri, yang ditulis dengan #. Engine yang menegakkannya: di luar class, obj.#field bahkan bukan sintaks yang valid, dan field itu tidak muncul di Object.keys, JSON.stringify, maupun console.log.

Menulis s.#token di luar class menghasilkan error TS18013 (Property '#token' is not accessible outside class 'Session' because it has a private identifier), dan tidak seperti private, tidak ada cara mengakalinya saat runtime juga. Lihat field private di JavaScript untuk aturan runtime-nya.

private vs #private: Mana yang Dipakai

private x#x
Diperiksa olehcompilerengine JavaScript
Terlihat oleh Object.keys / JSON.stringifyyatidak
Akses kurung siku obj["x"]diizinkantidak mungkin
Subclass bisa mendeklarasikan x miliknya sendiritidak, bentrokya, setiap class punya #x sendiri
Ikut tersalin oleh spread { ...obj }yatidak
Sintaks pada methodprivate helper()#helper()

Pakai #private kalau data harus tetap private saat runtime (token, state internal yang tidak boleh disentuh pengguna sebuah library) atau kalau kamu ingin JSON.stringify melewatinya. Pakai private kalau tujuannya hanya API publik yang rapi, kalau sebuah framework perlu membaca field itu secara reflektif, atau untuk menyamakan dengan gaya codebase yang sudah ada. Jangan menggabungkan keduanya: private #x menghasilkan error TS18010 (An accessibility modifier cannot be used with a private identifier).

protected dan Subclass

Member protected tersedia di dalam class dan di setiap class yang mewarisinya, tetapi tidak lewat instance dari luar.

Ada satu aturan yang sering mengejutkan. Di dalam Polygon, kamu bisa membaca sides pada this atau pada Polygon lain, tetapi tidak pada Shape biasa yang dikirim sebagai parameter: other.sides dengan other: Shape menghasilkan error TS2446 (Property 'sides' is protected and only accessible through an instance of class 'Polygon'. This is an instance of class 'Shape'.). Subclass hanya boleh menjangkau member protected dari objek yang berada di cabang hierarkinya sendiri.

Subclass bisa membuat member protected menjadi public dengan mendeklarasikannya ulang, tetapi tidak bisa membuat member public menjadi protected atau private. Deklarasikan ulang dengan nilai awal (public override sides = 6) atau hanya sebagai tipe (declare public sides: number). public sides: number; saja akan ditolak dengan TS2564 dan TS2612, karena dengan class field modern, deklarasi itu akan mengembalikan nilai warisan menjadi undefined setelah super() selesai.

readonly

readonly mencegah penugasan ulang setelah objek dibuat. Field bisa diberi nilai di deklarasinya atau di constructor; penugasan apa pun setelah itu menghasilkan error TS2540.

Ada dua batasan yang terlihat di sini. readonly bersifat dangkal: array-nya tidak bisa diganti, tetapi isinya bisa berubah (beri tipe readonly string[] untuk mencegah push). Dan seperti private, modifier ini hilang saat runtime, jadi penugasan yang ditolak compiler tetap dijalankan. Untuk nilai yang tidak boleh berubah saat runtime, pakai Object.freeze atau getter tanpa setter. Halaman readonly membahas Readonly<T> dan array readonly.

readonly bisa digabung dengan access modifier: private readonly cache = new Map<string, number>() adalah pola umum untuk field yang bersifat internal dan tidak pernah diberi nilai ulang.

Kesalahan Umum

  • Menganggap private sebagai keamanan. Modifier ini hilang saat runtime. Pakai #field untuk data yang harus tetap tersembunyi, dan jangan pernah mengirim objek berisi rahasia langsung ke JSON.stringify.
  • Menulis public di mana-mana. Itu sudah default; menambahkannya tidak mengubah apa pun.
  • Memakai protected untuk semua hal yang "internal". Kalau tidak ada subclass yang membutuhkannya, private membuat permukaan API lebih kecil.
  • Mengira readonly membekukan data bersarang. Modifier ini hanya mencegah penugasan ulang property itu sendiri.

Pertanyaan yang sering diajukan

Apa saja access modifier di TypeScript?

public (default: bisa diakses di mana saja), protected (di dalam class dan subclass-nya), dan private (hanya di dalam class). readonly adalah modifier terpisah yang mencegah penugasan ulang setelah constructor selesai, dan bisa digabung dengan salah satu dari ketiganya.

Apa bedanya private dan #private di TypeScript?

private hanya diperiksa oleh compiler; JavaScript hasil kompilasinya berisi property biasa, jadi obj["secret"], JSON.stringify, dan Object.keys tetap bisa melihatnya. #secret adalah field private JavaScript: runtime yang menegakkannya, dan kode di luar class sama sekali tidak bisa membacanya.

Apakah private di TypeScript benar-benar private?

Hanya saat kompilasi. Setelah dikompilasi, field itu menjadi property biasa yang bisa dibaca kode JavaScript mana pun. TypeScript bahkan mengizinkan akses dengan kurung siku (obj["field"]) ke member private sebagai jalan pintas. Pakai #field kalau sifat private-nya harus tetap berlaku saat runtime.

Apa bedanya protected dan private di TypeScript?

Member private hanya terlihat di dalam class yang mendeklarasikannya. Member protected juga terlihat di dalam subclass. Keduanya tidak bisa diakses lewat instance dari luar hierarki class.

Apakah property readonly bisa diubah di TypeScript?

Property readonly bisa diberi nilai di deklarasinya atau di constructor, dan tidak di tempat lain (selain itu muncul TS2540). Sifatnya dangkal: readonly tags: string[] tidak bisa diganti, tetapi tags.push() tetap berjalan. Pakai readonly string[] untuk mencegah itu juga.

Ilustrasi bahasa pemrograman di Coddy

Belajar coding dengan Coddy

Mulai