CodeBlanks Logo Icon CodeBlanks

Meydan okuma 3: Branded + phantom

Branded ve phantom türlerini birleştiren bir görev çözersin.

Branded + phantom türler

Branded türler, ilkel bir değere benzersiz bir sembol imzası ekleyerek aynı temel türe sahip ama karıştırılmaması gereken nominel türler yaratır. Phantom türler ise yalnızca derleme zamanında var olan ve çalışma zamanında kullanılmayan bir tür parametresiyle durumu kodlar.

declare const __brand: unique symbol;
type Brand<T, B> = T & { readonly [__brand]: B };

type UserId = Brand<string, "UserId">;
type OrderId = Brand<string, "OrderId">;
// UserId ve OrderId artık birbirine atanamaz

İkisini birleştirerek çalışma zamanında güvenli, derleme zamanında durum belirli API'ler kurabilirsin.

Uygulama Brand türü tanımla

__brand adında unique symbol tanımla ve Brand<T, B> = T & { readonly [__brand]: B } türünü yaz. UserId = Brand<string, "UserId"> ve Email = Brand<string, "Email"> alias'larını oluştur, her birinden bir değer yap ve uid'i yazdır.

Başlangıç kodu

index.ts
// Brand<T, B> tanımla
// UserId = Brand<string, "UserId">
// Email = Brand<string, "Email">
// her ikisinden bir değer oluştur, UserId değerini yazdır

Örnek çözüm

index.ts
declare const __brand: unique symbol;
type Brand<T, B> = T & { readonly [__brand]: B };

type UserId = Brand<string, "UserId">;
type Email = Brand<string, "Email">;

const uid: UserId = "u123" as UserId;
const em: Email = "a@b.com" as Email;
console.log(uid);

Beklenen çıktı

u123

Uygulama Phantom durumlu kutu

Box<S> türünü yaz: S "Open" | "Sealed" ile kısıtlı phantom parametre, Brand<{ value: number }, `Box_${S}`> olsun. open(b: Box<"Sealed">): Box<"Open"> fonksiyonu b.value'yu yeni bir kutu olarak döndürsün. Mühürlü bir kutu oluştur, open çağır ve value'yu yazdır.

Başlangıç kodu

index.ts
// Brand ve phantom birleştir
// Box<S>: S = "Open" | "Sealed" phantom durumu
// open: mühürlü kutuyu açılır kutuya çevirir
// bir mühürlü kutu oluştur, open çağır, value'yu yazdır

Örnek çözüm

index.ts
declare const __brand: unique symbol;
type Brand<T, B> = T & { readonly [__brand]: B };

type Box<S extends "Open" | "Sealed"> = Brand<{ value: number }, `Box_${S}`>;

function open(b: Box<"Sealed">): Box<"Open"> {
  return { value: b.value } as Box<"Open">;
}

const sealed: Box<"Sealed"> = { value: 7 } as Box<"Sealed">;
const opened = open(sealed);
console.log(opened.value);

Beklenen çıktı

7

Soru ve cevaplar

Dersin sorularını cevaplarıyla birlikte inceleyebilirsin. Kendini denemek istersen dersi interaktif olarak çöz.

1 Aşağıdaki tanımlardan sonra hangi satır derlenir?

index.ts
declare const __brand: unique symbol;
type Brand<T, B> = T & { readonly [__brand]: B };
type UserId = Brand<string, "UserId">;
type OrderId = Brand<string, "OrderId">;
  • let u: UserId = "x" as UserId; Doğru cevap
  • let u: UserId = 5 as UserId;
  • let u: UserId = "x" as OrderId;
  • let o: OrderId = "x" as UserId;

Açıklama: Branded türler nominel gibi davranır; yalnızca aynı markaya ve aynı temel türe sahip değerler birbirine atanabilir. Farklı marka veya yanlış temel tür derleme hatası verir.

2 Brand sembolü

Soru
declare const __brand: ____;
type Brand<T, B> = T & { readonly [__brand]: B };
Cevap
declare const __brand: unique symbol;
type Brand<T, B> = T & { readonly [__brand]: B };

Açıklama: Brand'in gerçekten benzersiz olması için `unique symbol` gerekir; sıradan `symbol` computed key olarak tür konumunda kullanılamaz.

3 Branded ve phantom parçaları

Kavram Anlamı
Branded type nominel davranış için sembol imzası
Phantom type çalışma zamanında kullanılmayan tür parametresi
unique symbol benzersiz anahtar garanti eder
as UserId değeri markalı türe yükseltir

İleri seviye bölümündeki tüm dersler