İçeriğe geç
academia.sh

Ders 06 / 23

Sabit Tipler ve as const

Tek değerli sabit tipler, as const ile genişletmenin durdurulması, sabit bir listeden birleşim tipi türetme ve satisfies işlecinin tip açıklamasından farkı.

İçindekiler

Ayırt edici birleşimin çalışması için alanların sabit tipte olması gerekiyordu. Tip çıkarımı dersi ise ters yönde bir kural koymuştu: nesne alanlarının tipi kendiliğinden genişletilir ve sabit tip kaybolur.

Bu ders bu gerilimi çözer. Önce sabit tiplerin ne olduğu netleştirilir, sonra genişletmeyi durduran as const yazımı, en sonunda da tipi daraltmadan sınayan satisfies işleci ele alınır.

Terim uyarısı: burada sabit tip (literal type) ile kastedilen, tek bir değeri içeren bir tiptir. Programlama Temelleri kursundaki sabit (constant) kavramıyla — program boyunca aynı değere bağlı ad — akrabadır ama aynı şey değildir; biri değerin tipiyle, diğeri bağlamanın değişmezliğiyle ilgilidir.

Sabit Tip Nedir

Her değerin, yalnızca kendisini içeren bir tipi vardır. "C" bir dizgi değeridir, "C" aynı zamanda tek elemanlı bir tiptir. Bu tiplere sabit tip denir ve dizgi, sayı ve mantıksal değerler için tanımlıdır.

Sabit tipler tek başlarına pek kullanışlı değildir — const x: "C" = "C" bildiriminin söylediği ek bir şey yoktur. Değerleri, birleşimde ortaya çıkar: "C" | "Pa" | "%" tipi, üç değerli bir kümedir ve dördüncü bir değeri reddeder.

Genişletme ve as const

Aynı nesne sabitinin iki biçimde bildirilmesi, çıkarılan tipleri karşılaştırmayı sağlar:

export const dogrudan = { kimlik: "s-01", birim: "C", deger: 21.4 };
export const dondurulmus = { kimlik: "s-01", birim: "C", deger: 21.4 } as const;
export const birimler = ["C", "Pa", "%"];
export const birimlerSabit = ["C", "Pa", "%"] as const;

Dosya sabit.ts adıyla kaydedilip tsc --strict --target es2022 --declaration --emitDeclarationOnly sabit.ts komutuyla derlendiğinde üretilen sabit.d.ts dosyası:

export declare const dogrudan: {
    kimlik: string;
    birim: string;
    deger: number;
};
export declare const dondurulmus: {
    readonly kimlik: "s-01";
    readonly birim: "C";
    readonly deger: 21.4;
};
export declare const birimler: string[];
export declare const birimlerSabit: readonly ["C", "Pa", "%"];

as const yazımı üç şeyi birden yapar:

  1. Alanların tiplerini genişletmez; her alan kendi sabit tipini korur.
  2. Tüm alanları salt okunur (readonly) işaretler.
  3. Dizi sabitini dizi değil demet olarak tipler: string[] yerine readonly ["C", "Pa", "%"].

Üçüncü madde önemlidir. birimler dizisinin tipi eleman sayısını unutmuştur; birimlerSabit demetinin tipi hem sayıyı hem sırayı hem de her konumun değerini bilir.

Salt okunur işaretlemesi de tip düzeyinde bir güvence sağlar:

const birimler = ["C", "Pa", "%"] as const;
birimler.push("F");
f2.ts(2,10): error TS2339: Property 'push' does not exist on type 'readonly ["C", "Pa", "%"]'.

as const Çalışma Zamanında Ne Bırakır

Kursun eksenini yeniden sınamak gerekir. Aşağıdaki dosya tsc --strict --target es2022 ac.ts ile derlendiğinde:

const birimler = ["C", "Pa", "%"] as const;
const olcum = { kimlik: "s-01", birim: "C" } as const;
console.log(birimler, olcum);

Üretilen JavaScript:

"use strict";
const birimler = ["C", "Pa", "%"];
const olcum = { kimlik: "s-01", birim: "C" };
console.log(birimler, olcum);

node ac.js çıktısı [ 'C', 'Pa', '%' ] { kimlik: 's-01', birim: 'C' } olur.

as const tamamen silinmiştir. Dizi çalışma zamanında sıradan bir dizidir; push çağrısı JavaScript tarafından kabul edilir. Salt okunurluk, derleyicinin gördüğü kodda geçerli bir sözdür — çalışma zamanı koruması değil. Gerçek değiştirilemezlik için Object.freeze gerekir ve o da yüzeyseldir.

Aynı sınır, as const ile işaretlenmiş bir değerin salt okunur olmayan bir tipe atanmasında da görülür:

type Birim = "C" | "Pa" | "%";
type Olcum = { kimlik: string; deger: number; birim: Birim };

const ham = { kimlik: "s-01", deger: 21.4, birim: "C" } as const;
const kayit: Olcum = ham;
console.log(kayit.birim);

kayit.deger = 22.1;
ham.deger = 22.1;
f6.ts(9,5): error TS2540: Cannot assign to 'deger' because it is a read-only property.

Sekizinci satır hata vermez. kayit bildiriminin tipi Olcumdur ve Olcum salt okunur değildir; aynı nesneye salt okunur olmayan bir başvuru elde edilmiştir. Salt okunurluk nesnenin değil, başvurunun özelliğidir.

Beşinci satırın kabul edilmesi ise as const yazımının çözdüğü asıl sorunu gösterir: as const olmadan birim alanı stringe genişler ve atama reddedilirdi.

Sabit Listeden Tip Türetme

as const ile bildirilmiş bir demetten, elemanlarının birleşimi olan bir tip türetilebilir:

const birimler = ["C", "Pa", "%"] as const;
type Birim = (typeof birimler)[number];

const gecerli: Birim = "Pa";
console.log(gecerli, birimler.length);

const gecersiz: Birim = "F";
f1.ts(7,7): error TS2322: Type '"F"' is not assignable to type '"C" | "Pa" | "%"'.

İki adım vardır. typeof birimler yazımı, bir değerin tipini alır — burada readonly ["C", "Pa", "%"]. Ardından [number] indeksi, demetin sayısal indeksle erişilebilen tüm elemanlarının tiplerinin birleşimini verir. Tanının "C" | "Pa" | "%" yazması bu türetmenin sonucudur.

Bu kalıbın değeri, aynı bilginin iki kez yazılmasını önlemesidir. Değerler listesi tek yerde durur; hem çalışma zamanında (döngüyle gezilebilir, doğrulamada kullanılabilir) hem de tip düzeyinde kullanılabilir. Numaralandırmanın verdiği “tüm değerleri sayabilme” yeteneği, çalışma zamanı kodu üretmeden elde edilmiş olur.

satisfies: Sınamak Ama Daraltmamak

Bir nesne sabitine tip yazmak iki şeyi birden yapar: sabiti sınar ve bildirimin tipini o tipe sabitler. İkincisi her zaman istenmez:

type Aralik = { alt: number; ust: number };

const aciklamali: Record<string, Aralik> = {
  sicaklik: { alt: -40, ust: 85 },
};

const sinanan = {
  sicaklik: { alt: -40, ust: 85 },
} satisfies Record<string, Aralik>;

console.log(aciklamali.nem.ust);
console.log(sinanan.nem.ust);
f4.ts(12,21): error TS2339: Property 'nem' does not exist on type '{ sicaklik: { alt: number; ust: number; }; }'.

On birinci satır hata vermez. aciklamali bildiriminin tipi Record<string, Aralik>tir; bu tip “her dizgi anahtar için bir aralık” der, dolayısıyla nem anahtarı da geçerli sayılır. Çalışma zamanında böyle bir anahtar yoktur ve program çöker.

satisfies işleci sabitin verilen tipe uyduğunu sınar, ama bildirimin tipini değiştirmez. sinanan bildiriminin tipi, sabitten çıkarılan dar tiptir; olmayan anahtara erişim on ikinci satırda yakalanır.

Sınama yönü de çalışır:

type Aralik = { alt: number; ust: number };

const araliklar = {
  sicaklik: { alt: -40, ust: "85" },
} satisfies Record<string, Aralik>;

console.log(araliklar.sicaklik.ust);
f5.ts(4,25): error TS2322: Type 'string' is not assignable to type 'number'.

Üç yazımın karşılaştırması:

Yazım Sabiti sınar Bildirimin tipi
const x: T = {...} Evet T
const x = {...} as T Hayır (zorlar) T
const x = {...} satisfies T Evet Sabitten çıkarılan dar tip

Orta satır ilk derste tanıtılan tip iddiasıdır ve bir borçtur. Alt satır, hem sınamayı hem de çıkarımın verdiği ayrıntıyı korur.

Özet

  • Sabit tip, tek bir değeri içeren tiptir; kullanışlılığı birleşim içinde ortaya çıkar ve bağlamanın değişmezliğini anlatan “sabit” kavramından ayrıdır.
  • as const yazımı genişletmeyi durdurur, alanları salt okunur işaretler ve dizi sabitlerini demet olarak tipler.
  • as const çalışma zamanında tamamen silinir; salt okunurluk nesnenin değil başvurunun özelliğidir ve gerçek değiştirilemezlik sağlamaz.
  • Sabit bir demetten (typeof x)[number] yazımıyla elemanlarının birleşimi türetilir; aynı bilgi hem değer hem tip düzeyinde tek yerde tutulur.
  • satisfies işleci sabiti verilen tipe karşı sınar ancak bildirimin dar tipini korur; tip açıklaması sınar ve genişletir, tip iddiası ise yalnızca zorlar.

Sonraki Adım

Bu konu, tek tek değerlerin tiplerini kurdu. Sırada bu tiplerin adlandırılması ve paylaşılması var: bir modülün dışa açtığı sözleşme nasıl yazılır, aynı sözleşmeyi karşılayan farklı gerçekleştirimler nasıl tanımlanır? Sonraki konu arayüzlerle başlayacak ve ölçüm kaydının modelini yeniden kullanılabilir bir sözleşmeye dönüştürecek.

İlerlemeni kaydetmek ve not almak için Giriş yap

Notlarım

Not almak için giriş yapmalısın.

Aramak için yazmaya başlayın.

↑↓ Esc gezin · aç · kapat