Type assertion, TypeScript'e bir değerin tipini sizin söylediğiniz gibi kabul etmesini bildirir: deger as Tip ya da .tsx dışındaki dosyalarda <Tip>deger. Derleme sırasında silinir ve çalışma zamanında hiçbir kontrol yapmaz; yanlış bir assertion hata fırlatmaz, sadece yanlış tipte bir değerle çalışmaya devam edersiniz. Bu yüzden mümkün olduğunda gerçek bir kontrolle tipi daraltmak (narrowing) daha güvenlidir.

Bu yazıda as ve açılı ayraç sözdizimini, TypeScript'in hangi dönüşümlere izin verdiğini, as unknown as T çift assertion'ını, as const (const assertion) kullanımını ve assertion yerine neyin tercih edilmesi gerektiğini TypeScript 6.0 ile derlenmiş örneklerle göreceksiniz.

as ve açılı ayraç sözdizimi

as ve açılı ayraç sözdizimi

Assertion genellikle TypeScript'in bilemeyeceği bir bilgiye sahip olduğunuzda kullanılır. JSON.parse any döndürdüğü için sonucu bir arayüze çevirmek tipik bir örnektir:

typescript
interface Ayar {
  port: number;
  host: string;
}

const metin = '{"port": 8080, "host": "localhost"}';
const ayar = JSON.parse(metin) as Ayar;
console.log(ayar.port + 1, ayar.host); // 8081 localhost

const ayar2 = <Ayar>JSON.parse(metin); // açılı ayraç: .tsx dosyasında kullanılamaz
console.log(ayar2.host);               // localhost

İki yazım eşdeğerdir. Açılı ayraç JSX sözdizimiyle çakıştığı için .tsx dosyalarında yalnızca as kullanılabilir; tutarlılık için çoğu projede her yerde as tercih edilir. Handbook'un tarayıcı örneği de benzerdir: document.getElementById yalnızca HTMLElement döndürür, sayfanızda o kimliğin bir HTMLCanvasElement olduğunu biliyorsanız as HTMLCanvasElement yazarsınız.

Hangi dönüşümlere izin verilir?

TypeScript yalnızca daha özel ya da daha genel bir tipe yapılan assertion'ları kabul eder. Birbiriyle hiç örtüşmeyen tipler arasındaki dönüşüm reddedilir:

typescript
const x = "merhaba" as number;
// TS2352: Conversion of type 'string' to type 'number' may be a mistake because
// neither type sufficiently overlaps with the other. If this was intentional,
// convert the expression to 'unknown' first.

Çift assertion: as unknown as T

Hata mesajının da önerdiği gibi önce unknown (veya any), sonra hedef tipe çevirerek bu kuralı aşabilirsiniz. Derleyici artık itiraz etmez, ama değer değişmez:

typescript
interface Kullanici { id: number; ad: string }

const girdi = "42";
const k = girdi as unknown as Kullanici; // derleyici kabul eder
console.log(typeof k, k.ad);              // string undefined

Assertion çalışma zamanında kontrol yapmaz

Assertion çalışma zamanında kontrol yapmaz: const a: T = deger, const a = deger as T, const a = deger satisfies T, deger!

Handbook bunu açıkça hatırlatır: assertion yanlışsa ne istisna oluşur ne de null üretilir. Gelen JSON beklediğiniz biçimde değilse hata çok daha ileride, ilgisiz görünen bir yerde ortaya çıkar:

typescript
interface Ayar { port: number; host: string }

const hatali = JSON.parse('{"prt": 8080}') as Ayar;
console.log(hatali.port);        // undefined
console.log(hatali.port + 1);    // NaN

Benzer bir tuzak, boş nesneyi assertion ile tam bir tipe çevirmektir. Tip ek açıklaması (annotation) eksik alanları yakalarken assertion yakalamaz:

typescript
interface Renk { ad: string; kod: string }
const r = {} as Renk;      // derleyici boş nesneyi Renk sayar
console.log(r.kod);        // undefined

const r2: Renk = {};
// TS2739: Type '{}' is missing the following properties from type 'Renk': ad, kod
YazımNe yaparEksik alanı yakalar mı
const a: T = degerDeğerin T ile uyumlu olduğunu denetlerEvet
const a = deger as TDeğeri T olarak kabul ederHayır
const a = deger satisfies TDenetler, çıkarılan tipi korurEvet
deger!null ve undefined kısmını tipten çıkarırHayır

satisfies operatörü, değeri bir tipe karşı denetlerken daha dar çıkarılmış tipi korur ve assertion'ın denetimsiz tarafından kaçınmanın iyi bir yoludur; ayrıntılar satisfies operatörü yazısında. Son ek ! için null, undefined ve strictNullChecks yazısına bakın.

Const assertion: as const

TypeScript 3.4 ile gelen as const, tip adı yerine const yazılan özel bir assertion'dır ve gerçek bir tip dönüşümü değil, daha dar bir çıkarım ister. Sürüm notlarına göre üç etkisi vardır: literal tipler genişletilmez ("merhaba" string olmaz), nesne değişmezlerinin özellikleri readonly olur ve dizi değişmezleri readonly tuple olur.

typescript
let a = "merhaba" as const;          // "merhaba"
let b = [10, 20] as const;           // readonly [10, 20]
let c = { yol: "/api", yontem: "GET" } as const;
// { readonly yol: "/api"; readonly yontem: "GET" }

declare function istek(yol: string, yontem: "GET" | "POST"): void;
istek(c.yol, c.yontem); // tamam

const d = { yol: "/api", yontem: "GET" };
istek(d.yol, d.yontem);
// TS2345: Argument of type 'string' is not assignable to parameter of type
// '"GET" | "POST"'.

d.yontem değişebilir bir özellik olduğu için string çıkarılır; as const bunu literal "GET" olarak sabitler. Bu kalıpla enum benzeri sabit nesneler de kurabilirsiniz:

typescript
const Durum = {
  Taslak: "taslak",
  Yayinda: "yayinda",
  Arsiv: "arsiv",
} as const;

type Durum = (typeof Durum)[keyof typeof Durum]; // "taslak" | "yayinda" | "arsiv"

function etiket(d: Durum) {
  return d.toUpperCase();
}
console.log(etiket(Durum.Yayinda)); // YAYINDA
console.log(Object.values(Durum));  // [ 'taslak', 'yayinda', 'arsiv' ]

as const yalnızca değişmezlere (literal) ve enum üyelerine uygulanabilir:

typescript
let sayi = Math.random() as const;
// TS1355: A 'const' assertion can only be applied to references to enum members,
// or string, number, boolean, array, or object literals.

Literal tiplerin genişletilmesi ve as const ile ilgili daha fazla örnek literal tipler ve as const yazısında, keyof typeof kalıbı keyof ve typeof yazısında, enum ile karşılaştırması enum ve alternatifleri yazısında.

Neden daraltma tercih edilmeli?

Assertion derleyiciye bir iddiada bulunur; daraltma ise iddiayı çalışma zamanında doğrular. Birleşim tipli bir parametreyi as ile tek tipe zorlamak, diğer olasılıkta sessizce yanlış sonuç verir:

typescript
function uzunluk(x: string | number) {
  return (x as string).length; // number gelirse undefined döner
}
console.log(uzunluk("abc"), uzunluk(12345)); // 3 undefined

function uzunluk2(x: string | number) {
  if (typeof x === "string") return x.length;
  return String(x).length;
}
console.log(uzunluk2("abc"), uzunluk2(12345)); // 3 5

Dış kaynaktan gelen veride (JSON.parse, ağ yanıtı) assertion yerine değeri unknown olarak alıp bir type guard fonksiyonuyla doğrulamak, hatayı verinin girdiği noktada yakalar:

typescript
interface Ayar { port: number; host: string }

function ayarMi(x: unknown): x is Ayar {
  return (
    typeof x === "object" && x !== null &&
    "port" in x && typeof x.port === "number" &&
    "host" in x && typeof x.host === "string"
  );
}

const ham: unknown = JSON.parse('{"prt": 8080}');
if (ayarMi(ham)) {
  console.log(ham.port + 1);
} else {
  console.log("geçersiz ayar"); // bu satır çalışır
}

Type guard, in ve typeof ile daraltmanın tüm biçimleri narrowing ve type guard yazısında; unknown tipinin neden any yerine tercih edildiği any, unknown ve never yazısında anlatılıyor.

catch değişkeni: as Error yerine instanceof

Assertion'ın en sık görüldüğü yerlerden biri catch bloğudur. TypeScript 4.4 sürüm notlarına göre strict açıkken etkin olan useUnknownInCatchVariables, catch değişkeninin tipini any yerine unknown yapar; çünkü JavaScript'te yalnızca Error nesneleri değil, herhangi bir değer fırlatılabilir. TypeScript 6.0 ile strict varsayılan olarak açık olduğu için bu davranış artık varsayılandır:

typescript
try {
  JSON.parse("{bozuk");
} catch (e) {
  console.log(e.message);
  // TS18046: 'e' is of type 'unknown'.
}

Sürüm notları burada üç yol sayar: çalışma zamanı kontrolü, type assertion veya değişkene açıkça : any yazmak. Kontrol yolu en güvenlisidir; assertion ise fırlatılan değerin gerçekten Error olduğunu varsayar:

typescript
try {
  JSON.parse("{bozuk");
} catch (e) {
  if (e instanceof SyntaxError) {
    console.log(e.name); // SyntaxError
  }
  console.log((e as Error).name); // SyntaxError (fırlatılan değer Error ise)
}

Fırlatılan değer bir metin olsaydı (e as Error).name ifadesi undefined verirdi, instanceof kontrolü ise bu durumu ayırt ederdi. Hata yönetiminin JavaScript tarafı try...catch ile hata yönetimi yazısında anlatılıyor.

Sık yapılan hatalar

Sık yapılan hatalar: Dış kaynaktan gelen veriyi (JSON.parse, API yanıtı) doğrulamadan as Tip ile..., Eksik alanları olan bir nesneyi {} as Tip ile başlatmak. Tip ek açıklaması...
  • Dış kaynaktan gelen veriyi (JSON.parse, API yanıtı) doğrulamadan as Tip ile kullanmak. Hata, verinin girdiği yerde değil çok daha ileride ortaya çıkar.
  • Eksik alanları olan bir nesneyi {} as Tip ile başlatmak. Tip ek açıklaması (const x: Tip = ...) eksik alanları yakalar, assertion yakalamaz.
  • TS2352 hatasını as unknown as ile susturup tip tanımındaki asıl sorunu düzeltmemek.
  • Birleşim tipli bir değeri as ile tek tipe zorlamak. typeof, in veya instanceof ile daraltma her olasılığı ele almanızı sağlar.
  • as const ifadesini değişkenler veya fonksiyon çağrıları üzerinde kullanmaya çalışmak (TS1355). Yalnızca değişmezlere uygulanır.

Assertion ne zaman makul?

  • Derleyicinin göremediği ama sizin kesin bildiğiniz bir bilgi varsa (örneğin sayfanızdaki belirli bir öğenin türü).
  • Bir test dosyasında, tamamı gerekmeyen büyük bir nesnenin sahte (mock) sürümünü kurarken.
  • Tip sisteminin ifade edemediği, ama başka bir yolla doğrulanmış dönüşümlerde. Bu durumda neden güvenli olduğunu bir yorumla yazın.
  • Literal tipleri korumak için as const; bu, değer hakkında yalan söylemediği için diğer assertion'lardan farklıdır.

Sık Sorulan Sorular

as ile tip dönüşümü (type casting) aynı şey mi?

Hayır. Diğer dillerdeki casting çoğunlukla değeri çevirir veya kontrol eder. TypeScript assertion'ı yalnızca derleyicinin bakışını değiştirir; çıktı JavaScript'te iz bırakmaz. Bir metni sayıya çevirmek için Number(metin) gibi gerçek bir dönüşüm gerekir; ayrıntılar JavaScript tip dönüşümü yazısında.

as any ile as unknown arasında fark var mı?

Handbook çift assertion için ikisini de ara adım olarak gösterir. Fark, assertion'ı tek başına kullandığınızda ortaya çıkar: as any o değer üzerindeki tüm tip denetimini kapatır ve sonraki her erişime izin verir, unknown ise kullanmadan önce daraltma ister. Ara adım gerekiyorsa unknown tercih etmek, hatanın başka satırlara yayılmasını önler. Bir değeri uzun süre any tutmak yerine sınırda bir kez doğrulamak daha güvenli bir alışkanlıktır.

as const ile Object.freeze aynı mı?

Değil. as const yalnızca tip düzeyinde readonly yapar ve derleme sonrası silinir; Object.freeze çalışma zamanında nesneyi dondurur. İkisini birlikte de kullanabilirsiniz.

Açılı ayraç sözdizimini neden görmüyorum?

Handbook'a göre <Tip>deger yazımı .tsx dosyalarında kullanılamaz. Hem .ts hem .tsx içeren projelerde tek yazım biçimi olarak as tercih edilir.

Assertion function (asserts x is T) bununla ilgili mi?

Adı benzer ama farklı bir özelliktir: TypeScript 3.7 ile gelen assertion fonksiyonları çalışma zamanında kontrol yapar, başarısız olursa hata fırlatır ve sonrasında tipi daraltır. Yani gerçek bir doğrulama içerir; narrowing yazısında ele alınıyor.

Marka adları sahiplerine aittir. Bu yazı bağımsız bir teknik rehberdir; adı geçen kuruluşlarla bayilik veya ortaklık ilişkisi bulunduğu anlamına gelmez.

İlgili içerikler: TypeScript öğrenme rehberi · satisfies operatörü · Narrowing ve type guard · Literal tipler ve as const · any, unknown ve never · strictNullChecks · TypeScript ileri seviye