TypeScript Template Literal Types

TypeScript Template Literal Types
Template literal type'lar, TypeScript 4.1 ile tanıtılan ve string literal type'ları programatik olarak oluşturmanızı sağlayan bir özelliktir. JavaScript template literal'larının tip seviyesindeki karşılığıdır. Bu yazıda template literal type'ların kullanımını ve pratik uygulamalarını detaylı örneklerle ele alacağız.
Temel Kullanım
// Basit template literal type
type Selamlama = `Merhaba, ${string}`;
let mesaj1: Selamlama = "Merhaba, Tarik"; // Geçerli
let mesaj2: Selamlama = "Merhaba, Dünya"; // Geçerli
// let mesaj3: Selamlama = "Günaydın, Tarik"; // HATA!
// Union ile template literal
type Renk = "kirmizi" | "mavi" | "yesil";
type Boyut = "kucuk" | "orta" | "buyuk";
type RenkBoyut = `${Renk}-${Boyut}`;
// "kirmizi-kucuk" | "kirmizi-orta" | "kirmizi-buyuk" |
// "mavi-kucuk" | "mavi-orta" | "mavi-buyuk" |
// "yesil-kucuk" | "yesil-orta" | "yesil-buyuk"
// Event adları
type Olay = "click" | "scroll" | "mousemove";
type OlayHandler = `on${Capitalize<Olay>}`;
// "onClick" | "onScroll" | "onMousemove"
Yerleşik String Manipulation Types
// Uppercase - tüm harfleri büyük yapar
type Buyuk = Uppercase<"merhaba">; // "MERHABA"
// Lowercase - tüm harfleri küçük yapar
type Kucuk = Lowercase<"MERHABA">; // "merhaba"
// Capitalize - ilk harfi büyük yapar
type BasHarfBuyuk = Capitalize<"merhaba">; // "Merhaba"
// Uncapitalize - ilk harfi küçük yapar
type BasHarfKucuk = Uncapitalize<"Merhaba">; // "merhaba"
// Kombinasyon
type CSSProperty = "backgroundColor" | "fontSize" | "borderRadius";
type CSSKebab = {
[K in CSSProperty as Uncapitalize<K>]: string;
};
// Getter/Setter oluşturma
type PropMethods<T> = {
[K in keyof T as `get${Capitalize<string & K>}`]: () => T[K];
} & {
[K in keyof T as `set${Capitalize<string & K>}`]: (value: T[K]) => void;
};
interface Kullanici {
isim: string;
yas: number;
}
type KullaniciMethods = PropMethods<Kullanici>;
// {
// getIsim: () => string;
// getYas: () => number;
// setIsim: (value: string) => void;
// setYas: (value: number) => void;
// }
Pattern Matching ile Template Literal
// String pattern matching
type ExtractRouteParams<T extends string> =
T extends `${string}:${infer Param}/${infer Rest}`
? Param | ExtractRouteParams<`/${Rest}`>
: T extends `${string}:${infer Param}`
? Param
: never;
type Params1 = ExtractRouteParams<"/kullanicilar/:id">;
// "id"
type Params2 = ExtractRouteParams<"/kullanicilar/:userId/yazilar/:postId">;
// "userId" | "postId"
// CSS değer parser
type ParsePixel<T extends string> =
T extends `${infer N}px` ? N : never;
type A = ParsePixel<"16px">; // "16"
type B = ParsePixel<"auto">; // never
// Dot notation path
type PathOf<T, Prefix extends string = ""> = {
[K in keyof T & string]: T[K] extends object
? PathOf<T[K], `${Prefix}${K}.`>
: `${Prefix}${K}`;
}[keyof T & string];
interface Ayarlar {
tema: {
renk: string;
font: string;
};
dil: string;
}
type AyarPathi = PathOf<Ayarlar>;
// "tema.renk" | "tema.font" | "dil"
Pratik Uygulamalar
// Tip güvenli event emitter
type EventMap = {
kullaniciGiris: { userId: number; zaman: Date };
kullaniciCikis: { userId: number };
siparisOlusturuldu: { siparisId: string; tutar: number };
};
type EventAdi = keyof EventMap;
type EventCallback<K extends EventAdi> = (data: EventMap[K]) => void;
class TipGuvenliEmitter {
private listeners = new Map<string, Function[]>();
on<K extends EventAdi>(event: K, callback: EventCallback<K>): void {
const existing = this.listeners.get(event) || [];
this.listeners.set(event, [...existing, callback]);
}
emit<K extends EventAdi>(event: K, data: EventMap[K]): void {
const callbacks = this.listeners.get(event) || [];
callbacks.forEach(cb => cb(data));
}
}
const emitter = new TipGuvenliEmitter();
emitter.on("kullaniciGiris", (data) => {
console.log(data.userId); // Tip güvenli!
});
// SQL sorgu builder (basitleştirilmiş)
type TableName = "kullanicilar" | "urunler" | "siparisler";
type SelectQuery = `SELECT * FROM ${TableName}`;
type WhereQuery = `${SelectQuery} WHERE ${string}`;
type OrderQuery = `${SelectQuery | WhereQuery} ORDER BY ${string}`;
Sonuç
Template literal type'lar, TypeScript tip sistemine string manipülasyonu yeteneği kazandırır. Basit string birleştirmelerden karmaşık pattern matching'e kadar geniş bir kullanım alanına sahiptir. String manipulation type'lar, mapped type'lar ve conditional type'lar ile birlikte kullanıldığında, inanılmaz derecede ifade gücü yüksek tip tanımlamaları yapmanızı sağlar.