Menu

TypeScript Interface Nedir: Sözdizimi, Opsiyonel Alanlar, Metotlar

Bir interface, bir nesnenin biçimine ad verir: hangi özelliklere sahip olduğunu ve bunların hangi tipleri tuttuğunu. Nasıl tanımlanacağını, opsiyonel ve readonly özellikleri, metotları, index signature'ları, genişletmeyi, bir sınıfta implement etmeyi, declaration merging'i, generic interface'leri ve bir interface'e nasıl varsayılan değer verileceğini öğrenin.

Bu sayfada çalıştırılabilir editörler var - düzenle, çalıştır ve sonucu anında gör.

Bir interface, bir nesnenin biçimine bir ad verir: sahip olması gereken özellikleri ve her birinin tipini. Tanımlandıktan sonra adı bir tip olarak kullanırsınız ve derleyici verdiğiniz, döndürdüğünüz veya atadığınız her nesneyi ona göre kontrol eder.

Son çağrı TS2741 derleme hatasıdır. Interface'ler kod derlendiğinde silinir: JavaScript çıktısında User tipinden hiçbir iz yoktur ve çalışma zamanında biçimi hiçbir şey kontrol etmez.

Interface Tanımlamak

Sözdizimi, interface anahtar kelimesi, bir ad (geleneksel olarak PascalCase) ve üyeleri listeleyen bir gövdeden oluşur. Üyeler noktalı virgül, virgül ya da yalnızca satır sonlarıyla ayrılabilir; yaygın stil noktalı virgüldür.

interface Product {
  sku: string;               // required property
  price: number;
  tags: string[];            // array property
  dimensions: {              // nested object type
    width: number;
    height: number;
  };
  discount?: number;         // optional property
  readonly createdAt: Date;  // cannot be reassigned
  label(): string;           // method
}

Bir interface bir tiptir, bir değer değildir. new ile örneklenemez, varsayılan değerleri yoktur ve obj instanceof Product TS2693 hatasıdır ('Product' only refers to a type, but is being used as a value here). Bir biçimi çalışma zamanında kontrol etmek için bir type guard yazın.

Yapısal Tipler ve Fazla Özellik Kontrolleri

TypeScript adları değil biçimleri karşılaştırır. Gerekli özelliklere sahip her nesne, onunla bildirilmiş olsun olmasın interface'e uyar. Fazla özellikler sorun değildir, bir istisna dışında: interface'in beklendiği yere doğrudan yazılan bir nesne literal'i fazla özellik kontrolünden geçer, çünkü orada bilinmeyen bir anahtar neredeyse her zaman bir yazım hatasıdır.

Bir User için { id: 1, name: "a", emial: "x" } hatasını yakalayan bu hatadır (TS2353): derleyici Did you mean to write 'email'? şeklinde öneride bile bulunur (TS2561).

Opsiyonel ve Readonly Özellikler

Addan sonraki bir ? bir özelliği opsiyonel yapar: nesne onu atlayabilir ve onu okumak T | undefined verir. readonly, nesne oluşturulduktan sonra özelliğin yeniden atanmasını yasaklar.

Burada iki sınır görünüyor. Birincisi, readonly yalnızca derleme zamanındadır: @ts-expect-error ile işaretlenmiş iki satır Run'a bastığınızda yine çalışır ve başarılı olur; son satırlar da apiUrl değerini readonly olmadan tiplenmiş bir referans üzerinden değiştirir. İkincisi, sığdır: readonly hosts: string[] yalnızca hosts değişkeninin yeniden atanmasını durdurur ama hosts.push(...) çağrısına yine izin verir; dizinin kendisinin readonly string[] olarak tiplenmesinin nedeni budur. Tipli kodda niyeti belgeler ve uygular; hiçbir şeyi dondurmaz. Readonly<T> utility tipi mevcut bir interface'in her özelliğini birden readonly yapar.

Metotlar ve Fonksiyon Özellikleri

Bir metot, bir metot imzası olarak, name(params): ReturnType, ya da bir fonksiyon tutan bir özellik olarak, name: (params) => ReturnType, yazılabilir. Çağıranlar ikisini de aynı şekilde kullanır.

Fark inceliklidir: strictFunctionTypes (strict kapsamında) altında fonksiyon tipli özelliklerin parametreleri katı şekilde kontrol edilir, metot imzaları ise daha gevşek (bivariant) kontrol edilir; bu yüzden özellik biçimi birkaç hatayı daha yakalar. Metot sözdizimi daha kısadır ve daha yaygın stildir; ikisi de uygundur.

Bir interface, bir call signature ya da bir construct signature kullanarak çağrılabilen veya oluşturulabilen bir şeyi de tanımlayabilir:

interface Formatter {
  (value: number): string; // call signature: the object is a function
  locale: string;          // and it also has a property
}

interface PointConstructor {
  new (x: number, y: number): { x: number; y: number }; // construct signature
}

Index Signature'lar

Özellik adları önceden bilinmediğinde, bir index signature hepsini birden tanımlar: [key: string]: T "her biri bir T tutan, herhangi bir string anahtar" anlamına gelir.

Son satırlar püf noktasını gösteriyor: var olmayan bir anahtarı okumak number | undefined olarak değil number olarak tiplenir. noUncheckedIndexedAccess derleyici seçeneği bu tür her okumaya | undefined ekler.

İsimli özellikler bir index signature'ın yanında durabilir ama ona uymaları gerekir. interface Dict { [key: string]: number; name: string } TS2411 hatasıdır, Property 'name' of type 'string' is not assignable to 'string' index type 'number'. Index tipini genişletin ([key: string]: number | string) ya da dinamik kısmı kendi özelliğine taşıyın. Basit anahtar/değer eşlemeleri için Record<string, number> aynı şeyi tek satırda söyler.

Bir Interface'i Genişletmek

extends bir veya daha fazla mevcut interface'ten yeni bir interface oluşturur. Çocuk, ebeveynin her üyesine ve kendi üyelerine sahip olur:

interface Animal {
  name: string;
}

interface Pet extends Animal {
  owner: string;
}

interface Trained {
  commands: string[];
}

interface ServiceDog extends Pet, Trained {
  certifiedUntil: Date;
}

// ServiceDog requires: name, owner, commands, certifiedUntil

Bir çocuk bir ebeveyn özelliğini yalnızca uyumlu (daha dar) bir tiple yeniden bildirebilir; örneğin ebeveynin kind: string dediği yerde kind: "dog". Kurallar ve type alias'ların nasıl genişletileceği extends sayfasında.

Bir Sınıfta Interface Implement Etmek

class X implements Shape, derleyiciden sınıfın interface'in gerektirdiği her şeye sahip olduğunu kontrol etmesini ister. Eksik bir üye, sınıf bildiriminde bir hatadır:

index.ts(7,7): error TS2420: Class 'Circle' incorrectly implements interface 'Shape'.
  Property 'area' is missing in type 'Circle' but required in type 'Shape'.

area() eklendiğinde birkaç sınıf, hatta düz bir nesne bile bir Shape olarak kullanılabilir:

implements yalnızca bir kontroldür. Sınıfa üye eklemez ve sınıfın metot parametrelerini sizin için tiplemez: greet(name: string): string implement eden bir sınıfın içindeki greet(name) {} yine TS7006 hatasıdır, Parameter 'name' implicitly has an 'any' type. Bir sınıf birden fazla interface implement edebilir: class A implements B, C.

Declaration Merging

Aynı kapsamda aynı adla iki kez interface tanımlamak ikisini tek bir interface'te birleştirir. Bu, type alias'ların yapamadığı bir şeydir (aynı adla ikinci bir type bir duplicate identifier hatasıdır).

interface Settings {
  theme: string;
}

interface Settings {
  fontSize: number;
}

// Settings now requires both properties
const s: Settings = { theme: "dark", fontSize: 14 };

Uygulama kodunda bu nadiren istediğiniz şeydir ve kazara bir birleştirme kafa karıştırıcı olabilir. Asıl kullanımı, sahibi olmadığınız tiplere üye eklemektir: bir kütüphanenin seçenekleri ya da Window gibi bir global. Bir modülün içinden bildirimi declare global ile sarın:

declare global {
  interface Window {
    analytics: { track(event: string): void };
  }
}

export {};

Bundan sonra window.analytics.track("signup") projenin her yerinde tip kontrolünden geçer. Tip tanım paketleri de aynı mekanizmaya dayanır; bkz. declaration dosyaları.

Interface Özellikleri İçin Varsayılan Değerler

Bir interface varsayılan değer tutamaz, çünkü tipleri tanımlar ve çalışma zamanında silinir. size?: "sm" | "md" = "md" TS1246 hatasıdır, An interface property cannot have an initializer. Özelliği opsiyonel yapın ve varsayılanı nesnenin kullanıldığı yerde doldurun:

Destructuring varsayılanları daha güvenli seçimdir: değer undefined olduğunda, açıkça verilmiş bir size: undefined dahil, her zaman uygulanırlar. Spread sürümü o açık undefined değerini varsayılanın üzerine kopyalar ve sonucu yine de size hep ayarlıymış gibi tiplenir. Bu garantiyi tiplerden almanız gerekiyorsa exactOptionalPropertyTypes seçeneğini açın; bu, opsiyonel bir size?: ... için size: undefined ifadesini derleme hatası yapar. Nesnenin davranışa da ihtiyacı olduğunda diğer seçenek, alanları başlatılmış bir sınıftır.

Generic Interface'ler

Bir interface tip parametreleri alabilir; bu da tek bir bildirimin pek çok veri tipiyle çalışmasını sağlar:

interface ApiResponse<T> {
  ok: boolean;
  data: T;
  error?: string;
}

interface Page<T> {
  items: T[];
  nextCursor?: string;
}

interface User {
  id: number;
  name: string;
}

const res: ApiResponse<Page<User>> = {
  ok: true,
  data: { items: [{ id: 1, name: "Ada" }], nextCursor: "abc" },
};

ApiResponse<Page<User>> "verisi bir kullanıcı sayfası olan bir yanıt" diye okunur. Standart kütüphane bunlarla doludur: Array<T>, Promise<T>, Map<K, V> hepsi generic interface'lerdir.

Interface ile Type Alias

Bir type alias'ı aynı nesne biçimini tanımlayabilir ve düz nesne tipleri için ikisi birbirinin yerine kullanılabilir. Yalnızca bir interface birleşebilir; yalnızca bir type alias bir union'a, bir tuple'a ya da mapped veya conditional bir tipe ad verebilir. TypeScript handbook'unun pratik kuralı, yalnızca type tipinin sahip olduğu bir özelliğe ihtiyaç duyana kadar interface kullanmaktır. Interface ile type sayfasında, çoğu insanı şaşırtan Record<string, ...> farkı dahil tam karşılaştırma var.

Sıkça Sorulan Sorular

TypeScript'te interface nedir?

Interface, bir nesnenin biçiminin adlandırılmış bir tanımıdır: özellik adları, tipleri, hangilerinin opsiyonel veya readonly olduğu ve metotları. Derleyici, o interface olarak kullanılan değerlerin bu biçime sahip olduğunu kontrol eder. Interface'ler yalnızca derleme zamanında vardır; hiç JavaScript üretmezler.

Bir TypeScript interface'inde varsayılan değer nasıl verilir?

Veremezsiniz: bir interface değerleri değil tipleri tanımlar, bu yüzden size: "md" = ... geçerli bir sözdizimi değildir. Özelliği opsiyonel yapın (size?: "sm" | "md") ve varsayılanı nesnenin kullanıldığı yerde uygulayın; genellikle fonksiyon parametrelerinde destructuring varsayılanlarıyla: function render({ size = "md" }: Options). Bir varsayılanlar nesnesini yaymak ({ ...DEFAULTS, ...options }) da çalışır, ama options içinde açıkça verilmiş bir undefined varsayılanın üzerine yazar.

Bir nesnenin bir interface'i implement ettiğini çalışma zamanında nasıl kontrol ederim?

Yerleşik bir yolu yoktur, çünkü interface'ler derleme sırasında silinir: obj instanceof User TS2693 hatasıdır ('User' only refers to a type, but is being used as a value here). Özellikleri kontrol eden bir type guard fonksiyonu yazın, function isUser(x: unknown): x is User { ... }, ya da bir şema kütüphanesiyle doğrulayın.

Bir interface birden fazla interface'i genişletebilir mi?

Evet. Onları extends sonrasında virgülle ayırarak listeleyin: interface ServiceDog extends Pet, Trained { ... }. Yeni interface her ebeveynin her üyesine ve kendi üyelerine sahip olur. İki ebeveyn aynı özelliği uyumsuz tiplerle bildiriyorsa bildirim hatalıdır.

TypeScript'te interface ile sınıf arasındaki fark nedir?

Bir sınıf çalışma zamanında vardır: bir constructor'ı, metot gerçeklemeleri vardır ve new ondan nesneler oluşturur. Bir interface ise yalnızca derleyici için bir biçim tanımlar ve JavaScript çıktısından silinir. Bir sınıf, derleyicinin uyumunu kontrol etmesi için implements SomeInterface bildirebilir; doğru biçime sahip her düz nesne de interface'e uyar.

Coddy programming languages illustration

Coddy ile kodlamayı öğren

BAŞLA