TypeScript Strict Kuralları
TypeScript projeleri için katı kural seti — tip disiplini, null/undefined tutarlılığı, yapı ve dosya organizasyonu, paket ekleme kriterleri, test disiplinleri, performans pragmatiği. CLAUDE.md / AGENTS.md / .cursorrules içeriği olarak kullanılır.
İçerik
Bu içeriği projenin CLAUDE.md / AGENTS.md / .cursorrules dosyasına yapıştır. AI araçları bu kuralları proje konteksti olarak otomatik okur.
TypeScript Çalışma Kuralları
tsconfig baseline
tsconfig.json içinde şu ayarlar açık olur:
{
"compilerOptions": {
"strict": true,
"noUncheckedIndexedAccess": true,
"noImplicitOverride": true,
"noFallthroughCasesInSwitch": true,
"noPropertyAccessFromIndexSignature": true,
"exactOptionalPropertyTypes": true,
"useUnknownInCatchVariables": true,
"isolatedModules": true,
"skipLibCheck": true
}
}
Gevşetme (örn. noUncheckedIndexedAccess: false) sadece açıklanan bir migration dönemi için — inline // TODO(typescript-strict): ... notu ile.
Tip disiplini
-
anyyasaktır. Emin değilsenunknownkullan ve narrow et.anygördüğün bir dosya = refactor fırsatı. -
ascast sadece:- Şema doğrulama (zod, valibot) sonrası
- External boundary'de (JSON response, DOM event, env var)
as constveas unknown as X(son çare double cast, yorum gerekir)
İç kodda cast görürsen refactor et.
-
Discriminated union > optional + if kontrol. "Bu alan şimdi var mı acaba" sorusunu kod okumakla değil tiple çöz:
// ❌ type Result = { ok: boolean; value?: User; error?: string }; // ✅ type Result = | { ok: true; value: User } | { ok: false; error: string }; -
Public API'lerde dönüş tipi explicit. Exported fonksiyonlar, route handler'lar, component prop'lar. Inline helper'larda inference kabul.
-
Generic constraint'leri gerçekten kısıtlayacak şekilde yaz —
<T>yerine<T extends { id: string }>ihtiyaç olduğunda.
Null / undefined tutarlılığı
- Projede biri seçilir — genellikle
undefined.| null | undefinedbirlikte nadiren. "Yok"u iki farklı şekilde ifade etme. - API response parse'ında nullability normalize edilir (zod
.nullable().transform(x => x ?? undefined)). - Non-null assertion
!yasaktır. Sebep varsa yorum ve tercih sırasıyla: type guard → early return →?? throw. ==ve!=yasaktır,===/!==kullan. Tek istisna:x == null(null + undefined check için) — projede karar verilip tutarlı kullanılır.
Yapı & dosya organizasyonu
export defaultyasak — Next.js'in dayattığı yerler hariç (page.tsx,layout.tsx,route.ts,middleware.ts).- Sebep: named export refactor / rename'de güvenli, barrel export anlamlı.
- Hot file: 300 satırı geçerse parçala. Tek bir dosyada 5+ component yok.
- Barrel export (
index.ts) sadece public API için. İç modül ağacı barrel'lanmaz (bundle size + import döngüsü riski). - Klasör yapısı pragmatik: feature-based > type-based.
components/UserCard/>components/ + hooks/ + types/. - Path alias
@/proje köküne. Göreli path../../üç seviyeyi geçiyorsa alias'a geç.
Naming
- Types / interfaces:
PascalCase—User,OrderItem - Types vs interfaces: default
type.interfaceyalnızca declaration merging ya da extend pattern'i gerektiğinde. - Props:
FooPropsekstansiyonu —UserCardProps - Variables / functions:
camelCase - Constants:
SCREAMING_SNAKE_CASEyalnızca gerçekten compile-time constant için — hepsi değil. - Boolean'lar:
is,has,can,shouldprefix'li —isLoading,hasAccess. - Event handler'lar:
handleXveyaonX— projede biri seçilir.
React / JSX kuralları (React kullanıyorsanız)
React.FC/FunctionComponentkullanma.function MyComponent(props: Props) { ... }yaz.- Props spreading:
<Comp {...props} />sadece known-safe prop'lar için. Arbitrary spread = tip kaybı. key={index}yasak (stable ID yoksaslugify(title)veyauuidv5).dangerouslySetInnerHTMLyorumlu, XSS kontrol edilmiş şekilde.
Paket ekleme kriterleri
Yeni paket eklemeden önce:
- Stdlib / framework built-in aynı işi yapıyor mu?
- Mevcut paket aynı işi yapıyor mu? (e.g.
date-fnsvarkenmomentekleme) - Son 18 ayda maintain edilmiş mi?
- Bundle size < 20KB gzip mi? Değilse gerekçe yaz.
- Security advisory var mı?
Package.json'a eklenen her bağımlılık PR description'da gerekçelendirilir.
Testler
- Tip testi ≠ runtime testi.
expectTypeOf(vitest) /tsdile tip testi ayrıdır. - Mock'lar yalan söyler. Boundary'de (HTTP, DB) mock kabul; iç kütüphanelerde mocklama, gerçeğini kullan.
- Snapshot testi sadece complex stable output için — UI snapshot'ı genelde gürültü.
- Test isimleri cümle formatında: "süresi geçmiş token reject edilir".
- Her bug fix bir regression test ile gelir.
Performans pragmatiği
Array.prototype.reduceokunaklı olmadıkçafor-ofkullan. Reduce her durumda doğru araç değil.- Derin kopya (
JSON.parse(JSON.stringify(...))) sadece küçük POJO için. Büyük yapılar içinstructuredClone, Immer veya structural sharing. - Memoization gerçekten gerekliyse.
useMemo/useCallbackher yerde ≠ performans, gürültü. - Bundle impact gözet:
lodashyerinelodash-es/...veya native.
Error handling
- Throw edilen her şey
Errorinstance'ı olsun.throw "message"yasak. - Custom error class'ları belirli kategoriler için:
ValidationError,NotFoundError,AuthError. try/catchile yutma yasak — ya handle et ya yukarı fırlat.console.error(e)+return nullanti-pattern.- Async'te
Promise.allbaşarısızlığı içinPromise.allSettleddüşünülür.
Logging
console.logprod kodunda yasak. Logger (pino/winston) veyaconsole.logyerinedebugkütüphanesi.- Log seviyesi:
debug,info,warn,error. Seviye bilinçli seçilir. - Structured log: serbest string değil
{ event, ...context }.
API ve veri sınırları
- Client'tan gelen JSON her zaman zod/valibot ile parse edilir.
as Responseyasak. - Dış API response'u da schema ile parse — dış servis kontratı değişirse anlarız.
- Environment variable'lar start-up'ta zod ile validate: eksik env → fast fail.
Commit & PR
- Conventional Commits + "neden". "what"ı diff söylüyor, mesaj "why" söyler.
- 72 karakter max başlık. Imperative mood. Nokta yok.
- Her PR kendi başına test edilebilir. Scope = 1 niyet.
Yasak listesi (özet)
anytipias Xiçeride (boundary dışı)- Non-null assertion
! ==/!=export default(Next.js exception dışı)throw "string"— Error olmalıconsole.logprod'daMath.random()/Date.now()test içinde (deterministik olmalı)ts-ignore/ts-expect-erroryorumsuz- 300+ satır dosya
- Barrel dışından geniş re-export