TypeScript, büyük ölçekli JavaScript uygulamaları geliştirmenin standardı haline geldi. Daha iyi ve daha sürdürülebilir TypeScript kodu yazmanıza yardımcı olacak modern en iyi pratikleri birlikte inceleyelim.
Neden TypeScript?
TypeScript, JavaScript'e statik tip denetimi ekleyerek şunları sağlar:
- Erken Hata Tespiti: Hataları çalışma zamanında değil, derleme zamanında yakalayın
- Daha İyi IDE Desteği: Otomatik tamamlama, yeniden düzenleme (refactoring) ve gezinme
- Gelişmiş Kod Dokümantasyonu: Tipler satır içi dokümantasyon görevi görür
- Artan Sürdürülebilirlik: Kodu anlamak ve değiştirmek daha kolaydır
Temel En İyi Pratikler
1. Strict Modu Kullanın
tsconfig.json dosyanızda strict modu her zaman etkinleştirin:
{ "compilerOptions": { "strict": true, "noUncheckedIndexedAccess": true, "noImplicitReturns": true, "noFallthroughCasesInSwitch": true } }
Bu, daha fazla hatayı yakalamanızı sağlar ve daha iyi pratikleri zorunlu kılar.
2. Nesne Yapıları için Interface Tercih Edin
Nesne tipleri için, özellikle kalıtım (extend) söz konusu olduğunda interface kullanın:
// Good interface User { id: string; name: string; email: string; } interface Admin extends User { permissions: string[]; } // Also fine for unions and intersections type Status = 'active' | 'inactive' | 'pending';
3. Discriminated Union'lar için Union Tiplerini Kullanın
Discriminated union'larla tip güvenli durum makineleri oluşturun:
type ApiResponse<T> = | { status: 'loading' } | { status: 'error'; error: string } | { status: 'success'; data: T }; function handleResponse<T>(response: ApiResponse<T>) { switch (response.status) { case 'loading': return 'Loading...'; case 'error': return `Error: ${response.error}`; case 'success': return response.data; // TypeScript knows data exists } }
4. Type Guard'lardan Yararlanın
Çalışma zamanında tip kontrolü için özel type guard'lar oluşturun:
interface Cat { type: 'cat'; meow: () => void; } interface Dog { type: 'dog'; bark: () => void; } type Animal = Cat | Dog; function isCat(animal: Animal): animal is Cat { return animal.type === 'cat'; } function makeSound(animal: Animal) { if (isCat(animal)) { animal.meow(); // TypeScript knows it's a Cat } else { animal.bark(); // TypeScript knows it's a Dog } }
5. const Assertion Kullanın
const assertion ile literal tipleri koruyun:
// Without const assertion const colors = ['red', 'green', 'blue']; // string[] // With const assertion const colors = ['red', 'green', 'blue'] as const; // readonly ["red", "green", "blue"] type Color = typeof colors[number]; // "red" | "green" | "blue"
6. Utility Tipler En Yakın Dostunuz
TypeScript güçlü utility tipler sunar:
interface User { id: string; name: string; email: string; age: number; } // Pick specific properties type UserPreview = Pick<User, 'id' | 'name'>; // { id: string; name: string; } // Omit properties type UserWithoutEmail = Omit<User, 'email'>; // Make all properties optional type PartialUser = Partial<User>; // Make all properties required type RequiredUser = Required<PartialUser>; // Make all properties readonly type ReadonlyUser = Readonly<User>; // Create a record type type UserRoles = Record<string, User>;
7. Generic Kısıtlamaları (Constraints)
Fonksiyonlarınızı hem esnek hem de tip güvenli hale getirmek için generic kısıtlamalarını kullanın:
// Bad: Too loose function getValue(obj: any, key: string) { return obj[key]; } // Good: Type-safe with generics function getValue<T, K extends keyof T>(obj: T, key: K): T[K] { return obj[key]; } const user = { name: 'John', age: 30 }; const name = getValue(user, 'name'); // Type: string const age = getValue(user, 'age'); // Type: number // getValue(user, 'invalid'); // Error: Argument of type 'invalid' is not assignable
8. Type Assertion'lardan Kaçının (Mümkün Olduğunca)
Type assertion'lar TypeScript'in tip denetimini devre dışı bırakır:
// Bad: Dangerous const data = apiResponse as User; // Better: Validate and type guard function isUser(data: unknown): data is User { return ( typeof data === 'object' && data !== null && 'id' in data && 'name' in data && 'email' in data ); } const data = apiResponse; if (isUser(data)) { // Now TypeScript knows data is User console.log(data.name); }
9. Template Literal Tiplerini Kullanın
Güçlü string tipleri oluşturun:
type Endpoint = 'users' | 'posts' | 'comments'; type Method = 'GET' | 'POST' | 'PUT' | 'DELETE'; type ApiRoute = `/api/${Endpoint}`; // "/api/users" | "/api/posts" | "/api/comments" type ApiMethod = `${Method} ${ApiRoute}`; // "GET /api/users" | "POST /api/users" | ... function callApi(route: ApiRoute, method: Method) { // Type-safe API calls } callApi('/api/users', 'GET'); // Valid // callApi('/api/invalid', 'GET'); // Error
10. Tipleri Namespace'lerle Düzenleyin
İlişkili tipleri bir arada tutun:
namespace Api { export interface Request { method: string; url: string; headers?: Record<string, string>; } export interface Response<T> { status: number; data: T; } export type ErrorResponse = Response<{ message: string }>; } function makeRequest(req: Api.Request): Promise<Api.Response<unknown>> { // Implementation }
İleri Düzey Kalıplar
Branded Tipler
TypeScript'in yapısal tip sisteminde nominal tipler oluşturun:
type UserId = string & { readonly brand: unique symbol }; type ProductId = string & { readonly brand: unique symbol }; function getUserById(id: UserId) { // Implementation } const userId = 'user-123' as UserId; const productId = 'prod-456' as ProductId; getUserById(userId); // OK // getUserById(productId); // Error: Type 'ProductId' is not assignable to type 'UserId'
Builder Kalıbı
Metot zincirlemeyle tip güvenli builder'lar:
class QueryBuilder<T> { private filters: ((item: T) => boolean)[] = []; where(predicate: (item: T) => boolean): this { this.filters.push(predicate); return this; } execute(data: T[]): T[] { return data.filter(item => this.filters.every(filter => filter(item)) ); } } const users = new QueryBuilder<User>() .where(u => u.age > 18) .where(u => u.active) .execute(allUsers);
Sonuç
TypeScript, doğru kullanıldığında kod kalitenizi ve geliştirici deneyiminizi ciddi ölçüde iyileştirebilen güçlü bir araçtır. Bu en iyi pratikler size şu konularda yardımcı olacak:
- Daha sürdürülebilir kod yazmak
- Hataları daha erken yakalamak
- Ekip içi iş birliğini geliştirmek
- Uygulamalarınızı güvenle ölçeklendirmek
Unutmayın: iyi TypeScript kodu, tip güvenliği ile pragmatizm arasında doğru dengeyi bulmakla ilgilidir. Tiplerinizi gereğinden fazla karmaşıklaştırmayın; ancak gerçek değer kattıkları yerlerde TypeScript'in güçlü özelliklerinden yararlanmaktan da çekinmeyin.
Bu pratikleri bugünden itibaren uygulamaya başlayın ve TypeScript kodunuzun daha sağlam, daha sürdürülebilir ve üzerinde çalışması daha keyifli hale gelişini izleyin!

