TypeScript'te bilmeniz gereken numaralandırmanın dört farklı yönü vardır. İlk olarak, bazı tanımlar:
"arama nesnesi"
Bu sıralamayı yazarsanız:
enum Foo { X, Y }
TypeScript aşağıdaki nesneyi yayınlayacaktır:
var Foo;
(function (Foo) {
Foo[Foo["X"] = 0] = "X";
Foo[Foo["Y"] = 1] = "Y";
})(Foo || (Foo = {}));
Buna arama nesnesi olarak değineceğim . Onun iki amacı vardır: Bir eşleştirme olarak hizmet dizeleri için numaralar yazarken mesela, Foo.X
ya da Foo['X']
, ve bir eşleme olarak hizmet numaraları için dizeleri . Bu ters eşleme, hata ayıklama veya günlüğe kaydetme amaçları için kullanışlıdır - genellikle değere sahip olursunuz 0
veya 1
karşılık gelen dizeyi "X"
veya "Y"
.
"bildirmek" veya " ortam "
TypeScript'te, derleyicinin bilmesi gereken şeyleri "bildirebilir", ancak aslında kod gönderemezsiniz. Bu, jQuery gibi $
hakkında tür bilgisi istediğiniz, ancak derleyici tarafından oluşturulan herhangi bir koda ihtiyaç duymayan bazı nesneleri (örneğin ) tanımlayan kitaplıklarınız olduğunda kullanışlıdır . Spesifikasyon ve diğer belgeler, bir "ortam" bağlamında bu şekilde yapılan bildirimlere atıfta bulunur; Bir .d.ts
dosyadaki tüm bildirimlerin "ambient" olduğuna dikkat etmek önemlidir ( declare
bildirim türüne bağlı olarak, açık bir değiştirici gerektirir veya bunu örtük olarak içerir).
"İnlining"
Performans ve kod boyutu nedenleriyle, derlendiğinde bir numaralandırma üyesine referansın sayısal eşdeğeri ile değiştirilmesi genellikle tercih edilir:
enum Foo { X = 4 }
var y = Foo.X; // emits "var y = 4";
Spesifikasyon bu ikameyi çağırıyor , ben buna satır içi diyeceğim çünkü daha havalı geliyor. Bazen olur değil sıralama değeri API gelecekteki bir sürümüne değişebilir çünkü enum üyeleri örneğin satır içine yerleştirilmiş istiyorum.
Enums, nasıl çalışıyorlar?
Bunu bir sıralamanın her bir yönüne göre ayıralım. Ne yazık ki, bu dört bölümün her biri diğerlerinin hepsinden terimlere başvuracak, bu yüzden muhtemelen tüm bunları birden fazla okumanız gerekecek.
hesaplanan ve hesaplanmayan (sabit)
Enum üyeleri hesaplanabilir veya hesaplanamaz . Spec olmayan bilgisayarlı üyeleri çağırır sabiti , ama onları arayacağım olmayan bilgisayarlı ile önlemek karışıklığa Kat .
Bir bilgisayarlı numaralama elemanı değeri derleme zamanında bilinen bir bileşiktir. Elbette, hesaplanan üyelere referanslar satır içi olamaz. Bunun aksine, bir sigara bilgisayarlı numaralama üyesidir değeri bir kez olan derleme zamanında da bilinir. Hesaplanmayan üyelere yapılan referanslar her zaman satır içi olarak yazılmıştır.
Hangi numaralandırma üyeleri hesaplanır ve hangileri hesaplanmaz? İlk olarak, bir const
numaralamanın tüm üyeleri , adından da anlaşılacağı gibi sabittir (yani hesaplanmamıştır). Sabit olmayan bir enum için, bir ambient (bildirim) enumuna mı yoksa ortam olmayan bir enum'a mı baktığınıza bağlıdır .
A'nın bir üyesi declare enum
(yani, ortam sıralaması), ancak ve ancak bir başlatıcıya sahipse sabittir . Aksi takdirde hesaplanır. A'da declare enum
yalnızca sayısal başlatıcılara izin verildiğini unutmayın. Misal:
declare enum Foo {
X, // Computed
Y = 2, // Non-computed
Z, // Computed! Not 3! Careful!
Q = 1 + 1 // Error
}
Son olarak, non-const enum'lerin üyeleri her zaman hesaplanmış olarak kabul edilir. Ancak, derleme zamanında hesaplanabilirlerse, başlangıç ifadeleri sabitlere indirgenir. Bu, const olmayan enum üyelerinin hiçbir zaman satır içi olmadığı anlamına gelir (bu davranış TypeScript 1.5'te değişti, alttaki "TypeScript'teki Değişiklikler" konusuna bakın)
sabit ve sabit olmayan
const
Bir enum bildirimi const
değiştiriciye sahip olabilir . Bir numaralandırma ise const
, üyelerine yapılan tüm referanslar satır içinde.
const enum Foo { A = 4 }
var x = Foo.A; // emitted as "var x = 4;", always
const numaralandırmalar derlendiğinde bir arama nesnesi üretmez. Bu sebeple Foo
üye referansının bir parçası olmadıkça yukarıdaki kodda referans verilmesi hatadır . Çalışma Foo
zamanında hiçbir nesne olmayacak.
const olmayan
Bir numaralandırma bildirimi const
değiştiriciye sahip değilse , üyelerine yapılan başvurular yalnızca üye hesaplanmamışsa satır içi olur. Const olmayan, bildirim olmayan bir enum bir arama nesnesi oluşturur.
ilan et (ortam) vs beyan edilmeyen
Önemli bir önsöz, declare
TypeScript'te çok özel bir anlama sahiptir: Bu nesne başka bir yerde var . Mevcut nesneleri tanımlamak içindir . declare
Gerçekte var olmayan nesneleri tanımlamak için kullanmanın kötü sonuçları olabilir; Bunları daha sonra keşfedeceğiz.
bildirmek
A declare enum
, bir arama nesnesi yayınlamaz. Bu üyeler hesaplanmışsa üyelerine yapılan referanslar satır içi olarak yazılmıştır (bilgisayarlı ve hesaplanmayanlar için yukarıya bakın).
Bu bir referans o diğer formları unutmamak gerekir declare enum
edilir , örneğin bu kodu izin değil bir derleme hatası ama olacak zamanında başarısız:
// Note: Assume no other file has actually created a Foo var at runtime
declare enum Foo { Bar }
var s = 'Bar';
var b = Foo[s]; // Fails
Bu hata "Derleyiciye yalan söylemeyin" kategorisine girer. Çalışma Foo
zamanında adlandırılmış bir nesneniz yoksa, yazmayın declare enum Foo
!
A declare const enum
, const enum
--preserveConstEnums haricinde a'dan farklı değildir (aşağıya bakın).
olmayan beyan
Bildirilmemiş bir enum, değilse bir arama nesnesi üretir const
. Satır içi yukarıda açıklanmıştır.
--preserveConstEnums bayrağı
Bu bayrağın tam olarak bir etkisi vardır: beyan edilmeyen sabit numaralandırmalar bir arama nesnesi yayınlar. Satır içi etkilenmez. Bu, hata ayıklama için kullanışlıdır.
Genel hatalar
En yaygın hata, declare enum
normal enum
veya const enum
daha uygun olduğunda a kullanmaktır . Yaygın bir biçim şudur:
module MyModule {
// Claiming this enum exists with 'declare', but it doesn't...
export declare enum Lies {
Foo = 0,
Bar = 1
}
var x = Lies.Foo; // Depend on inlining
}
module SomeOtherCode {
// x ends up as 'undefined' at runtime
import x = MyModule.Lies;
// Try to use lookup object, which ought to exist
// runtime error, canot read property 0 of undefined
console.log(x[x.Foo]);
}
Altın kuralı hatırlayın: Gerçekte var olmayan şeyleri asladeclare
. const enum
Her zaman satır içi yapmak istiyorsanız veya enum
arama nesnesini istiyorsanız kullanın .
TypeScript'teki değişiklikler
TypeScript 1.4 ve 1.5 arasında, sabit olmayan tanımlı olmayan numaralandırmaların tüm üyelerinin hesaplanmış olarak değerlendirilmesini sağlamak için davranışta bir değişiklik oldu (bkz. Https://github.com/Microsoft/TypeScript/issues/2183 ) bir değişmez ile açıkça başlatılırlar. Bu, tabiri caizse "bebeği ayırdı", satır içi davranışı daha öngörülebilir hale getiriyor ve kavramını const enum
normalden daha net bir şekilde ayırıyor enum
. Bu değişiklikten önce, sabit olmayan numaralandırmaların hesaplanmamış üyeleri daha agresif bir şekilde satır içine alınmıştı.