"TypeScript'e geçmeli miyiz?" sorusu artık geçerliliğini yitirdi. 2026'da doğru soru şu: "Neden hâlâ geçmedik?" Bu yazıda TypeScript'in neden artık bir tercih değil zorunluluk olduğunu, JavaScript'te karşılaşılan gerçek hataları ve adım adım geçiş stratejisini ele alıyoruz.
JavaScript'in Problemi: Runtime Hataları
JavaScript dinamik tipli bir dil. Bu esneklik küçük scriptlerde avantaj olsa da, büyüyen projelerde kabusa dönüşür.
Gerçek Dünya Hata Örnekleri
1. Undefined is not a function — Klasik JavaScript kabusun:
// JavaScript — runtime'da patlıyor
function getUser(id) {
return fetch(`/api/users/${id}`)
.then(res => res.json());
}
// Geliştirici user.name yerine user.username yazdı
// Kod review'da farkedilmedi, production'a çıktı
async function displayUser() {
const user = await getUser(1);
document.getElementById("name").textContent = user.username;
// undefined — ama hata vermez, sadece "undefined" yazar
}
// TypeScript — derleme zamanında yakalar
interface User {
id: number;
name: string;
email: string;
}
async function getUser(id: number): Promise<User> {
const res = await fetch(`/api/users/${id}`);
return res.json();
}
async function displayUser() {
const user = await getUser(1);
document.getElementById("name")!.textContent = user.username;
// TS Error: Property 'username' does not exist on type 'User'.
// Did you mean 'name'?
}
TypeScript, bu hatayı siz kodu kaydettiğiniz anda, IDE'de kırmızı çizgiyle gösteriyor. Production'a çıkması imkansız.
2. API Yanıt Uyumsuzluğu:
// JavaScript — API yanıtı değişirse ne olur?
// Backend ekibi "price" alanını "amount" olarak değiştirdi
// Frontend'de hiçbir hata vermez, sadece undefined gösterir
function displayProduct(product) {
return `${product.name} - ${product.price} TL`;
// "Laptop - undefined TL" — sessizce bozulur
}
// TypeScript — API tipi ile sözleşme
interface Product {
id: string;
name: string;
amount: number; // "price" → "amount" olarak güncellendi
currency: string;
}
function displayProduct(product: Product): string {
return `${product.name} - ${product.price} TL`;
// TS Error: Property 'price' does not exist on type 'Product'.
// IDE anında 42 dosyada bu hatayı gösterir
}
3. Yanlış Tip ile Fonksiyon Çağrısı:
// JavaScript — sessizce yanlış çalışır
function calculateDiscount(price, discount) {
return price * (1 - discount / 100);
}
// Geliştirici string gönderdi
calculateDiscount("100", "20");
// Sonuç: NaN veya beklenmeyen değer
// TypeScript — hatalı kullanımı engeller
function calculateDiscount(price: number, discount: number): number {
return price * (1 - discount / 100);
}
calculateDiscount("100", "20");
// TS Error: Argument of type 'string' is not assignable to parameter of type 'number'.
Sayılarla TypeScript'in Etkisi
Araştırmalar ve sektörel veriler TypeScript'in etkisini net gösteriyor:
- Airbnb: JavaScript'ten TypeScript'e geçişte hataların %38'inin TypeScript tarafından önlenebileceğini tespit etti
- Bloomberg: TypeScript geçişi sonrası production bug sayısında %40 azalma raporladı
- GitHub 2025 Raporu: TypeScript, JavaScript'i geçerek en popüler dil oldu
- Stack Overflow 2025: Geliştiricilerin %73'ü TypeScript'i tercih ediyor
- npm: Yeni paketlerin %85'i TypeScript desteğiyle yayınlanıyor
TypeScript'in Temel Faydaları
1. Otomatik Tamamlama ve Dökümantasyon
TypeScript ile IDE'niz (VS Code) mükemmel otomatik tamamlama sunar. Bir objenin hangi property'lere sahip olduğunu, bir fonksiyonun hangi parametreleri aldığını ve ne döndüğünü anında görürsünüz.
interface BlogPost {
id: number;
title: string;
slug: string;
content: string;
tags: string[];
publishedAt: Date | null;
author: {
name: string;
avatar: string;
};
}
// IDE otomatik tamamlama — post. yazdığınızda tüm alanları gösterir
function formatPost(post: BlogPost) {
// post. → id, title, slug, content, tags, publishedAt, author
// post.author. → name, avatar
return `${post.title} by ${post.author.name}`;
}
2. Güvenli Refactoring
Bir fonksiyon adını, bir property ismini veya bir tipi değiştirdiğinizde, TypeScript tüm projede etkilenen yerleri anında gösterir. "Find and Replace" ile tahmin yürütmeye gerek yok.
3. Dokümantasyon Olarak Tipler
TypeScript tipleri, yaşayan dokümantasyon görevi görür:
// Fonksiyonun ne aldığı ve ne döndüğü açık
type OrderStatus = "pending" | "processing" | "shipped" | "delivered" | "cancelled";
interface CreateOrderInput {
customerId: string;
items: Array<{
productId: string;
quantity: number;
unitPrice: number;
}>;
shippingAddress: Address;
paymentMethod: "credit_card" | "bank_transfer" | "cash_on_delivery";
}
interface Order extends CreateOrderInput {
id: string;
status: OrderStatus;
totalAmount: number;
createdAt: Date;
}
async function createOrder(input: CreateOrderInput): Promise<Order> {
// Fonksiyon imzası her şeyi anlatıyor
// JSDoc yazmaya gerek yok
}
4. Union Types ve Discriminated Unions
TypeScript'in en güçlü özelliklerinden biri:
// API yanıtları için mükemmel pattern
type ApiResponse<T> =
| { status: "success"; data: T }
| { status: "error"; message: string; code: number }
| { status: "loading" };
function handleResponse(response: ApiResponse<User>) {
switch (response.status) {
case "success":
// TypeScript bilir: response.data User tipinde
console.log(response.data.name);
break;
case "error":
// TypeScript bilir: response.message ve response.code var
console.error(`Hata ${response.code}: ${response.message}`);
break;
case "loading":
// TypeScript bilir: sadece status var
console.log("Yükleniyor...");
break;
}
}
5. Generics ile Yeniden Kullanılabilir Kod
// Herhangi bir veri tipiyle çalışan genel fonksiyonlar
function paginate<T>(items: T[], page: number, perPage: number): {
data: T[];
total: number;
currentPage: number;
totalPages: number;
} {
const start = (page - 1) * perPage;
const data = items.slice(start, start + perPage);
return {
data,
total: items.length,
currentPage: page,
totalPages: Math.ceil(items.length / perPage),
};
}
// TypeScript tipi otomatik çıkarır
const userPage = paginate(users, 1, 10);
// userPage.data → User[]
const productPage = paginate(products, 2, 20);
// productPage.data → Product[]
JavaScript'ten TypeScript'e Geçiş Stratejisi
Aşama 1: Hazırlık (1 hafta)
# TypeScript'i projeye ekleyin
npm install -D typescript @types/react @types/node
# tsconfig.json oluşturun — gevşek ayarlarla başlayın
npx tsc --init
{
"compilerOptions": {
"strict": false,
"allowJs": true,
"checkJs": false,
"noEmit": true,
"esModuleInterop": true,
"moduleResolution": "bundler",
"jsx": "preserve",
"incremental": true,
"target": "ES2022",
"lib": ["ES2022", "DOM", "DOM.Iterable"]
},
"include": ["src/**/*"],
"exclude": ["node_modules"]
}
Önemli: strict: false ile başlayın. İlk günden strict mode açmak, yüzlerce hata ile karşılaşmanıza ve motivasyon kaybetmenize neden olur.
Aşama 2: Kademeli Dönüşüm (2-4 hafta)
Strateji: Yeni dosyaları .ts/.tsx olarak oluşturun, mevcut .js dosyalarını kademeli olarak dönüştürün.
Öncelik sırası:
- Paylaşılan tipler — API yanıtları, veri modelleri için tip dosyaları oluşturun
- Utility fonksiyonlar — En çok kullanılan yardımcı fonksiyonları dönüştürün
- API katmanı — fetch wrapper'ları ve API istemcisini tip güvenli yapın
- Component'ler — Yaprak component'lerden başlayarak yukarı çıkın
// types/api.ts — merkezi tip tanımları
export interface User {
id: string;
name: string;
email: string;
role: "admin" | "user" | "editor";
createdAt: string;
}
export interface PaginatedResponse<T> {
data: T[];
pagination: {
page: number;
perPage: number;
total: number;
totalPages: number;
};
}
// lib/api.ts — tip güvenli API istemcisi
export async function fetchApi<T>(
endpoint: string,
options?: RequestInit
): Promise<T> {
const res = await fetch(`${API_BASE_URL}${endpoint}`, {
headers: { "Content-Type": "application/json" },
...options,
});
if (!res.ok) {
throw new Error(`API Error: ${res.status}`);
}
return res.json();
}
// Kullanım — tam tip güvenliği
const users = await fetchApi<PaginatedResponse<User>>("/users?page=1");
// users.data → User[]
// users.pagination.totalPages → number
Aşama 3: Strict Mode (4-8 hafta)
Dönüşüm %80'e ulaştığında, tsconfig.json'da strict mode'u açın:
{
"compilerOptions": {
"strict": true,
"noUncheckedIndexedAccess": true,
"exactOptionalPropertyTypes": true
}
}
Strict mode şunları zorlar:
strictNullChecks:nullveundefinedkontrollerinoImplicitAny: Açık tip tanımı olmayan değişkenleri engellerstrictFunctionTypes: Fonksiyon parametre tiplerini katı kontrol eder
Araç Önerileri
| Araç | Kullanım |
|---|---|
| VS Code | TypeScript'in en iyi IDE desteği |
| ESLint + typescript-eslint | TypeScript'e özel lint kuralları |
| Prettier | Otomatik kod formatlama |
| ts-prune | Kullanılmayan export'ları tespit etme |
| type-coverage | Tip kapsama oranını ölçme |
| zod | Runtime tip validasyonu (API sınırları) |
TypeScript + Next.js: Mükemmel Uyum
Next.js, TypeScript'i birinci sınıf vatandaş olarak destekler. Sayfa tipleri, API route tipleri ve konfigürasyon dosyaları tamamen tip güvenli:
// app/blog/[slug]/page.tsx — Next.js 16 + TypeScript
import { Metadata } from "next";
import { notFound } from "next/navigation";
interface Props {
params: Promise<{ slug: string }>;
}
export async function generateMetadata({ params }: Props): Promise<Metadata> {
const { slug } = await params;
const post = await getPost(slug);
if (!post) return {};
return {
title: post.title,
description: post.excerpt,
openGraph: {
title: post.title,
description: post.excerpt,
type: "article",
publishedTime: post.date,
},
};
}
export default async function BlogPostPage({ params }: Props) {
const { slug } = await params;
const post = await getPost(slug);
if (!post) notFound();
return (
<article>
<h1>{post.title}</h1>
<time dateTime={post.date}>{formatDate(post.date)}</time>
<div dangerouslySetInnerHTML={{ __html: post.content }} />
</article>
);
}
Sonuç
TypeScript, 2026'da JavaScript projelerinde standart haline geldi. Büyük şirketlerden freelance geliştiricilere kadar herkes geçiş yapıyor. Sebebi basit: daha az hata, daha hızlı geliştirme, daha kolay bakım. Geçişi ertelemek, biriktirilen teknik borcun artması demek.
Maviona olarak tüm projelerimizde TypeScript kullanıyoruz. Müşterilerimize teslim ettiğimiz kodun güvenilir, bakımı kolay ve hatasız olmasını sağlamak için bu bir zorunluluk.
Projenizi TypeScript'e taşımak veya sıfırdan TypeScript tabanlı bir proje başlatmak istiyorsanız, Maviona ile iletişime geçin.
