İçeriğe geç
academia.sh

Ders 08 / 23

Tip Takma Adları

type bildiriminin arayüzden farkları: her tipi adlandırabilme, bildirim birleştirmenin bulunmaması, döngüsel başvuru kuralları, takma adla sınıf sözleşmesi ve seçim ölçütü.

İçindekiler

Aynı ölçüm modeli önceki konuda type ile, bu konunun ilk dersinde interface ile yazıldı. İki bildirim biçimi çoğu durumda birbirinin yerine geçer; eşdeğer değildirler.

Tip takma adı (type alias), var olan bir tipe ad veren bildirimdir. Yeni bir tip yaratmaz — type Kimlik = string bildiriminden sonra Kimlik ile string aynı tiptir ve birbirinin yerine kullanılabilir. Arayüz ise adlandırılmış bir nesne tipi tanımlar. Bu ders, farkın nerede ortaya çıktığını ve hangisinin ne zaman seçileceğini kurar.

Her Tipi Adlandırabilme

Takma ad, herhangi bir tipe ad verebilir. Arayüz yalnızca nesne ve çağrılabilir yapıları tanımlayabilir:

type Birim = "C" | "Pa" | "%";
type Kimlik = string;
type Aralik = [alt: number, ust: number];
type Donusturucu = (deger: number) => number;

const birim: Birim = "C";
const aralik: Aralik = [-40, 85];
const kelvine: Donusturucu = (d) => d + 273.15;

console.log(birim, aralik, kelvine(21.4));

Çıktı:

C [ -40, 85 ] 294.54999999999995

Dördünün hiçbiri arayüzle yazılamaz. Birleşim, ilkel tip ve demet nesne tipi değildir; fonksiyon tipi arayüzle yazılabilir ama çok daha uzun bir yazım gerektirir. Sonraki konudaki eşlenmiş, koşullu ve şablon dizgi tipleri de yalnızca takma adla adlandırılabilir.

Çıktının son değerine dikkat: 21.4 + 273.15 işlemi 294.55 değil 294.54999999999995 verir. Tip sistemi number tipini doğru saymıştır; kayan noktalı gösterimin kesinlik sınırı ise onun alanı değildir. Bu, ilk derste sayılan “kanıtlanmayanlar” listesinin somut bir örneğidir.

Bildirim Birleştirme Yok

Arayüzler aynı adla yeniden bildirilip birleştirilebiliyordu. Takma adlarda bu yoktur:

type Olcum = { kimlik: string };
type Olcum = { deger: number };
h2.ts(1,6): error TS2300: Duplicate identifier 'Olcum'.
h2.ts(2,6): error TS2300: Duplicate identifier 'Olcum'.

Tanı iki kez gelir, çünkü her iki bildirim de çakışmanın tarafıdır.

Bu, takma adın sınırı değil güvencesidir: bir takma adın tanımı, yazıldığı yerde tamdır. Başka bir dosyanın o tipe alan eklemesi olanaksızdır. Kendi kod tabanının veri modellerinde bu öngörülebilirlik genellikle istenir.

Karşı yönde, bir arayüz genişletme yoluyla takma addan türetilebilir:

type SayisalOlcum = { kimlik: string; deger: number };

interface ZamanliOlcum extends SayisalOlcum {
  zaman: number;
}

const k: ZamanliOlcum = { kimlik: "s-01", deger: 21.4, zaman: 1 };
console.log(k);

Bu dosya hatasız derlenir. Ancak takma ad bir nesne tipi değilse genişletme başarısız olur:

type SayisalOlcum = { kimlik: string; deger: number };
type MetinselOlcum = { kimlik: string; metin: string };
type Kayit = SayisalOlcum | MetinselOlcum;

interface Genisletme extends Kayit {
  zaman: number;
}
h7.ts(5,30): error TS2312: An interface can only extend an object type or intersection of object types with statically known members.

Bir birleşimi genişletmenin anlamı yoktur: Genisletme tipinin hangi üyeyi devralacağı belirsizdir. Aynı işlemi kesişimle yazmak ise geçerlidir — type Genisletme = Kayit & { zaman: number } bildirimi, her iki üyeye zaman alanı ekleyen bir birleşim üretir.

Döngüsel Başvuru

Ölçüm kayıtları iç içe geçen bir yapıya dönüştüğünde, tip kendisine başvurmak zorunda kalır. Nesne alanı içindeki başvuru geçerlidir:

type OlcumDugumu = {
  kimlik: string;
  deger: number;
  altKayitlar: OlcumDugumu[];
};

const kok: OlcumDugumu = {
  kimlik: "kazan-2",
  deger: 21.4,
  altKayitlar: [{ kimlik: "s-01", deger: 21.4, altKayitlar: [] }],
};

function toplamDugum(dugum: OlcumDugumu): number {
  return 1 + dugum.altKayitlar.reduce((t, a) => t + toplamDugum(a), 0);
}

console.log(toplamDugum(kok));

Dosya hatasız derlenir, çıktısı 2dir.

Buna karşılık doğrudan döngüsel bir başvuru reddedilir:

type Zincir = Zincir | null;
declare const z: Zincir;
console.log(z);
h3.ts(1,6): error TS2456: Type alias 'Zincir' circularly references itself.

Ayrım şudur: OlcumDugumu başvurusu bir nesne alanının içindedir ve derleyici o alanın tipini yalnızca gerektiğinde çözer. Zincir bildirimi ise kendi tanımını çözmek için yine kendini gerektirir; sonlanmayan bir açılımdır. Özyinelemeli tip tanımlarının kuralları İleri Tipler konusunda ayrıntılı ele alınacaktır.

Takma Adla Sınıf Sözleşmesi

Bir sınıfın karşılayacağı sözleşme takma adla da yazılabilir. Takma ad bir nesne tipini adlandırdığı sürece implements bildirimi arayüzdekiyle aynı biçimde çalışır:

type Olcum = { kimlik: string; deger: number };

class DosyaKaydi implements Olcum {
  constructor(
    readonly kimlik: string,
    readonly deger: number,
  ) {}
}

const kayit: Olcum = new DosyaKaydi("s-01", 21.4);
console.log(kayit.kimlik, kayit.deger);

Çıktı s-01 21.4tür.

Sınır, genişletmedeki sınırla aynıdır: takma ad bir birleşimi adlandırıyorsa gerçekleştirilemez.

type SayisalOlcum = { kimlik: string; deger: number };
type MetinselOlcum = { kimlik: string; metin: string };
type Kayit = SayisalOlcum | MetinselOlcum;

class DosyaKaydi implements Kayit {
  constructor(readonly kimlik: string) {}
}
u2.ts(5,29): error TS2422: A class can only implement an object type or intersection of object types with statically known members.

Gerekçe de aynıdır: sınıfın hangi üyeyi karşılayacağı belirsizdir. Bir sınıfın “ya şu ya bu biçimde” olması, tek bir bildirimle ifade edilemez. Böyle bir modelde sözleşme, birleşimin her üyesi için ayrı sınıflarla karşılanır ve birleşim yalnızca değer düzeyinde kullanılır.

Seçim Ölçütü

İki bildirim biçimi arasındaki farklar bir tabloda toplanabilir:

Ölçüt interface type
Nesne tipi tanımlar Evet Evet
Birleşim, demet, ilkel adlandırır Hayır Evet
Aynı adla yeniden bildirim Birleşir TS2300
Genişletme extends (bildirimde sınanır) & (sessizce indirgenir)
Sınıfla gerçekleştirme implements implements (nesne tipiyse)
Eşlenmiş, koşullu tip Hayır Evet

Tablodan uygulanabilir bir ölçüt çıkar:

Nesne biçimindeki sözleşmeler için arayüz. Bir veri kaydının alanları, bir servisin sunduğu yöntemler, bir sınıfın karşılayacağı sözleşme. Genişletme sınandığı için hatalar bildirim anında yakalanır; tanı iletileri ad taşır.

Diğer her şey için takma ad. Birleşimler, ayırt edici birleşimler, demetler, fonksiyon tipleri, tip düzeyinde hesaplanan tipler. Bu tiplerin arayüz karşılığı ya yoktur ya zorlamadır.

Bu kursta ölçüm kaydının kendisi arayüzle, durumları ve türetilmiş tipleri takma adla yazılacaktır:

interface Olcum {
  readonly kimlik: string;
  sensor: string;
  deger: number;
  birim: "C" | "Pa" | "%";
  zaman: number;
}

type OlcumDurumu =
  | { durum: "gecerli"; olcum: Olcum }
  | { durum: "hatali"; kimlik: string; kod: string };

function ozet(kayit: OlcumDurumu): string {
  return kayit.durum === "gecerli"
    ? `${kayit.olcum.kimlik}=${kayit.olcum.deger}${kayit.olcum.birim}`
    : `${kayit.kimlik}: ${kayit.kod}`;
}

console.log(
  ozet({
    durum: "gecerli",
    olcum: {
      kimlik: "s-01",
      sensor: "sicaklik",
      deger: 21.4,
      birim: "C",
      zaman: 1706000000000,
    },
  }),
);
console.log(ozet({ durum: "hatali", kimlik: "s-02", kod: "E17" }));

Çıktı:

s-01=21.4C
s-02: E17

İki bildirim biçiminin iş bölümü burada görülür: Olcum bir kaydın biçimidir ve büyüyebilir; OlcumDurumu ise kapalı bir seçenek kümesidir ve büyümesi kasıtlı bir karar olmalıdır.

Özet

  • Tip takma adı var olan bir tipe ad verir; birleşim, demet, ilkel ve fonksiyon tipleri dahil her tipi adlandırabilir.
  • Arayüzler aynı adla yeniden bildirilip birleşir; takma adın ikinci bildirimi TS2300 tanısı verir ve bu, tanımın tek yerde tam olmasını güvenceye alır.
  • Bir arayüz nesne tipindeki takma adı genişletebilir; birleşim tipini genişletemez.
  • Nesne alanı içindeki döngüsel başvuru geçerlidir; doğrudan döngüsel takma ad TS2456 tanısı verir.
  • Nesne tipini adlandıran bir takma ad implements ile gerçekleştirilebilir; birleşimi adlandıran takma ad TS2422 tanısı verir.
  • Ölçüt: nesne biçimindeki sözleşmeler arayüzle, birleşimler ve tip düzeyinde hesaplanan tipler takma adla yazılır.

Sonraki Adım

Buraya kadarki sözleşmeler yalnızca veriyi ve işlem imzalarını tanımladı; gerçekleştirim her seferinde ayrı bir fonksiyondan geldi. Sınıflar bu ikisini bir arada tutar ve TypeScript, sınıflara görünürlük denetimi ekler. Sonraki ders erişim belirteçlerini, soyut sınıfları ve bunların derlenmiş çıktıda ne bıraktığını ele alacak.

İ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