TypeScript memiliki banyak cara berbeda untuk menentukan enum:
enum Alpha { X, Y, Z }
const enum Beta { X, Y, Z }
declare enum Gamma { X, Y, Z }
declare const enum Delta { X, Y, Z }
Jika saya mencoba menggunakan nilai dari Gamma
saat runtime, saya mendapatkan kesalahan karena Gamma
tidak ditentukan, tetapi bukan itu masalahnya Delta
atau Alpha
? Apa maksud const
atau declare
maksud deklarasi di sini?
Ada juga tanda preserveConstEnums
kompilator - bagaimana ini berinteraksi dengan ini?
enums
typescript
Ryan Cavanaugh
sumber
sumber
Jawaban:
Ada empat aspek berbeda untuk enum di TypeScript yang perlu Anda waspadai. Pertama, beberapa definisi:
"objek pencarian"
Jika Anda menulis enum ini:
TypeScript akan memancarkan objek berikut:
Saya akan merujuk ini sebagai objek pencarian . Tujuannya ada dua: berfungsi sebagai pemetaan dari string ke angka , misalnya saat menulis
Foo.X
atauFoo['X']
, dan berfungsi sebagai pemetaan dari angka ke string . Pemetaan terbalik itu berguna untuk tujuan debugging atau logging - Anda akan sering memiliki nilai0
atau1
dan ingin mendapatkan string yang sesuai"X"
atau"Y"
."menyatakan" atau " ambient "
Dalam TypeScript, Anda dapat "mendeklarasikan" hal-hal yang harus diketahui oleh compiler, tetapi tidak benar-benar mengeluarkan kode. Ini berguna ketika Anda memiliki pustaka seperti jQuery yang mendefinisikan beberapa objek (misalnya
$
) yang Anda inginkan informasinya diketik, tetapi tidak memerlukan kode apa pun yang dibuat oleh kompiler. Spesifikasi dan dokumentasi lainnya mengacu pada deklarasi yang dibuat dengan cara ini sebagai konteks "ambient"; penting untuk dicatat bahwa semua deklarasi dalam.d.ts
file bersifat "ambient" (baik membutuhkandeclare
pengubah eksplisit atau memilikinya secara implisit, tergantung pada jenis deklarasi)."inlining"
Untuk alasan performa dan ukuran kode, sering kali lebih baik jika referensi ke anggota enum diganti dengan padanan numeriknya saat dikompilasi:
Spek menyebut substitusi ini , saya akan menyebutnya sebaris karena terdengar lebih keren. Terkadang Anda tidak ingin anggota enum menjadi sebaris, misalnya karena nilai enum mungkin berubah di versi API yang akan datang.
Enums, bagaimana cara kerjanya?
Mari kita uraikan ini dengan setiap aspek enum. Sayangnya, masing-masing dari empat bagian ini akan mereferensikan istilah-istilah dari yang lainnya, jadi Anda mungkin perlu membaca keseluruhan ini lebih dari sekali.
dihitung vs tidak dihitung (konstan)
Anggota enum dapat dihitung atau tidak. Spec memanggil anggota yang tidak dihitung konstan , tetapi saya akan menyebutnya non-dihitung untuk menghindari kebingungan dengan const .
Sebuah dihitung anggota enum adalah salah satu yang nilainya tidak diketahui pada saat kompilasi. Referensi ke anggota yang dihitung tidak dapat disisipkan, tentu saja. Sebaliknya, non-computed anggota enum sekali yang nilainya adalah dikenal pada saat kompilasi. Referensi ke anggota yang tidak dihitung selalu sebaris.
Anggota enum mana yang dihitung dan mana yang tidak dihitung? Pertama, semua anggota
const
enum adalah konstan (yaitu tidak dihitung), seperti namanya. Untuk enum non-konst, itu tergantung pada apakah Anda melihat enum ambien (deklarasikan) atau enum non-ambien.Anggota a
declare enum
(yaitu enum ambien) konstan jika dan hanya jika memiliki penginisialisasi. Jika tidak, itu dihitung. Perhatikan bahwa dalam adeclare enum
, hanya penginisialisasi numerik yang diperbolehkan. Contoh:Akhirnya, anggota non-deklarasikan non-const enum selalu dianggap dihitung. Namun, ekspresi inisialisasi mereka dikurangi menjadi konstanta jika dapat dihitung pada waktu kompilasi. Artinya, anggota enum non-konst tidak pernah sebaris (perilaku ini diubah di TypeScript 1.5, lihat "Perubahan di TypeScript" di bagian bawah)
const vs non-const
const
Deklarasi enum dapat memiliki
const
pengubah. Jika enum adalahconst
, semua referensi ke anggotanya disisipkan.const enums tidak menghasilkan objek pencarian saat dikompilasi. Karena alasan ini, adalah kesalahan untuk merujuk
Foo
pada kode di atas kecuali sebagai bagian dari referensi anggota. Tidak adaFoo
objek yang akan hadir saat runtime.non-const
Jika deklarasi enum tidak memiliki
const
pengubah, referensi ke anggotanya hanya sebaris jika anggota tersebut tidak dihitung. Enum non-const, non-deklarasikan akan menghasilkan objek pencarian.menyatakan (ambient) vs non-deklarasikan
Kata pengantar yang penting adalah bahwa
declare
di TypeScript memiliki arti yang sangat spesifik: Objek ini ada di tempat lain . Ini untuk mendeskripsikan objek yang ada . Menggunakandeclare
untuk mendefinisikan objek yang sebenarnya tidak ada dapat memiliki konsekuensi yang buruk; kita akan menjelajahinya nanti.menyatakan
A
declare enum
tidak akan memancarkan objek pencarian. Referensi ke anggotanya menjadi inline jika anggota tersebut dihitung (lihat di atas di computed vs non-computed).Sangat penting untuk dicatat bahwa bentuk-bentuk lain dari referensi untuk
declare enum
yang diperbolehkan, misalnya kode ini tidak error kompilasi tapi akan gagal saat runtime:Kesalahan ini termasuk dalam kategori "Jangan berbohong pada kompiler". Jika Anda tidak memiliki objek bernama
Foo
saat runtime, jangan menulisdeclare enum Foo
!A
declare const enum
tidak berbeda dari aconst enum
, kecuali dalam kasus --preserveConstEnums (lihat di bawah).non-deklarasikan
Enum yang tidak mendeklarasikan menghasilkan objek pencarian jika tidak
const
. Sebaris dijelaskan di atas.--preserveConstEnums
Bendera ini memiliki satu efek: non-deklarasikan enum const akan memancarkan objek pencarian. Sebaris tidak terpengaruh. Ini berguna untuk debugging.
Kesalahan Umum
Kesalahan paling umum adalah menggunakan a
declare enum
when a regularenum
atauconst enum
akan lebih tepat. Bentuk umum adalah ini:Ingat aturan emas: Jangan pernah
declare
hal-hal yang sebenarnya tidak ada . Gunakanconst enum
jika Anda selalu ingin sebaris, atauenum
jika Anda menginginkan objek pencarian.Perubahan TypeScript
Antara TypeScript 1.4 dan 1.5, ada perubahan dalam perilaku (lihat https://github.com/Microsoft/TypeScript/issues/2183 ) untuk membuat semua anggota non-deklarasikan enum non-konst diperlakukan sebagai dihitung, bahkan jika mereka secara eksplisit diinisialisasi dengan literal. Ini "memisahkan bayi", sehingga membuat perilaku inlining lebih dapat diprediksi dan lebih jelas memisahkan konsep
const enum
dari biasaenum
. Sebelum perubahan ini, anggota non-konstanta enum yang tidak dihitung dimasukkan lebih agresif.sumber
enum
jenis, terima kasih!const
jenis enum yang tepat untuk dideklarasikan.Ada beberapa hal yang terjadi di sini. Mari kita lanjutkan kasus per kasus.
enum
Pertama, enum tua biasa. Saat dikompilasi ke JavaScript, ini akan mengeluarkan tabel pencarian.
Tabel pemeta terlihat seperti ini:
Kemudian ketika Anda memiliki
Cheese.Brie
TypeScript, itu memancarkanCheese.Brie
dalam JavaScript yang mengevaluasi 0.Cheese[0]
emitCheese[0]
dan benar-benar mengevaluasi ke"Brie"
.const enum
Tidak ada kode yang benar-benar dikeluarkan untuk ini! Nilainya segaris. Yang berikut ini mengeluarkan nilai 0 itu sendiri di JavaScript:
const enum
s 'inlining mungkin berguna untuk alasan kinerja.Tapi bagaimana dengan
Bread[0]
? Ini akan error saat runtime dan compiler Anda harus menangkapnya. Tidak ada tabel pemeta dan kompilator tidak sebaris di sini.Perhatikan bahwa dalam kasus di atas, flag --preserveConstEnums akan menyebabkan Bread mengeluarkan tabel pencarian. Nilainya akan tetap inline.
nyatakan enum
Seperti penggunaan lainnya
declare
,declare
tidak mengeluarkan kode dan mengharapkan Anda untuk menentukan kode sebenarnya di tempat lain. Ini tidak memancarkan tabel pencarian:Wine.Red
memancarkanWine.Red
dalam JavaScript, tetapi tidak akan ada tabel pencarian Wine untuk referensi sehingga ini adalah kesalahan kecuali Anda telah menetapkannya di tempat lain.deklarasikan const enum
Ini tidak memancarkan tabel pencarian:
Tapi itu sebaris!
Fruit.Apple
memancarkan 0. Tapi sekali lagiFruit[0]
akan error saat runtime karena tidak inline dan tidak ada tabel lookup.Saya telah menulis ini di taman bermain ini . Saya sarankan bermain di sana untuk memahami TypeScript mana yang memancarkan JavaScript.
sumber
Bread[0]
muncul kesalahan compiler: "Anggota const enum hanya dapat diakses menggunakan string literal."