TypeScript'te modül davranışını iki ayar belirler. module, derlenen JavaScript'in hangi modül biçiminde (ESM veya CommonJS) yazılacağını ve çalışma ortamının dosyaları nasıl yorumlayacağını derleyiciye anlatır. moduleResolution ise import içindeki yolun (module specifier) diskteki hangi dosyaya karşılık geldiğini nasıl bulacağını seçer. Node.js'te doğrudan çalışacak kod için "module": "nodenext", bir bundler (Vite, esbuild, Webpack gibi) veya Bun ile işlenecek kod için "module": "esnext" (ya da preserve) ile "moduleResolution": "bundler" önerilir.
Bu yazıda TypeScript 6.0'ın yeni varsayılanlarını, kullanımdan kaldırılan seçenekleri, ESM ile CommonJS arasındaki farkı ve import yollarındaki dosya uzantısı kuralını tsc 6.0'ın gerçek hata mesajlarıyla anlatıyoruz. import/export sözdiziminin kendisi için JavaScript ES modülleri yazısına, serinin tamamı için TypeScript öğrenme rehberi sayfasına bakabilirsiniz.
Temel fikir: TypeScript import yolunu değiştirmez

Modules Theory belgesinin vurguladığı nokta şudur: TypeScript import ve export deyimlerini başka bir modül biçimine çevirebilir, ama from sonrasındaki metni olduğu gibi bırakır. Yani yazdığınız yol, derlenmiş .js dosyası çalışırken de geçerli olmalıdır. Bu yüzden TypeScript, çalışma ortamının (host) modül çözümleme kurallarını taklit eder ve tipleri bulmak için .js yolunu kaynak .ts veya .d.ts dosyasına eşler. Örneğin "./mod.js" için önce mod.ts, mod.tsx, mod.d.ts aranır.
TypeScript 6.0'da değişen varsayılanlar
TypeScript 6.0 sürüm notlarına göre module artık varsayılan olarak esnext. moduleResolution belirtmediğimiz bir projede --traceResolution çıktısında derleyicinin "Module resolution kind is not specified, using 'Bundler'." yazdığını gördük. Ayrıca eski çözümleme modları kullanımdan kaldırıldı:
$ tsc -p . # "moduleResolution": "node" ile
error TS5107: Option 'moduleResolution=node10' is deprecated and will stop functioning in TypeScript 7.0.
Specify compilerOption '"ignoreDeprecations": "6.0"' to silence this error.
$ tsc -p . # "moduleResolution": "classic" ile
error TS5107: Option 'moduleResolution=classic' is deprecated and will stop functioning in TypeScript 7.0.
Specify compilerOption '"ignoreDeprecations": "6.0"' to silence this error.Sürüm notları node (node10) kullananların Node.js hedefliyorsa nodenext'e, bundler veya Bun kullanıyorsa bundler'a geçmesini önerir. module değerlerinden amd, umd, systemjs ve none da kaldırıldı. "ignoreDeprecations": "6.0" hatayı şimdilik susturur ama bu seçenekler TypeScript 7.0'da tamamen kalkacak. 6.0'ın diğer değişiklikleri için TypeScript 6.0 yenilikleri yazısına bakın.
Node.js için: module nodenext

Node.js her dosyanın ESM mi CommonJS mi olduğunu uzantıya ve en yakın package.json dosyasındaki type alanına bakarak belirler. module değeri node16, node18, node20 veya nodenext olduğunda TypeScript aynı kuralı kaynak dosyalara uygular:
| Kaynak dosya | Çıktı | Biçim |
|---|---|---|
| .mts | .mjs | Her zaman ESM |
| .cts | .cjs | Her zaman CommonJS |
| .ts (package.json içinde "type": "module") | .js | ESM |
| .ts (type alanı yok veya farklı) | .js | CommonJS |
Küçük bir ESM projesi kuralım. package.json içinde "type": "module" var ve tsconfig şöyle:
{
"compilerOptions": {
"module": "nodenext",
"rootDir": "./src",
"outDir": "./dist"
},
"include": ["src"]
}// src/matematik.ts
export function topla(a: number, b: number) {
return a + b;
}
// src/main.ts
import { topla } from "./matematik";
// TS2835: Relative import paths need explicit file extensions in ECMAScript imports when
// '--moduleResolution' is 'node16' or 'nodenext'. Did you mean './matematik.js'?
console.log(topla(2, 3));Node.js ESM içinde göreli yolların uzantıyla yazılmasını şart koştuğu için TypeScript de bunu ister. Doğru yazım, kaynak dosya .ts olsa bile çıktının uzantısını kullanmaktır: import { topla } from "./matematik.js";. Bu düzeltmeyle derlenen dist/main.js aynı import satırını içerir ve node dist/main.js komutu 5 yazdırır. Yola .ts yazarsanız şu hatayı alırsınız:
error TS5097: An import path can only end with a '.ts' extension when 'allowImportingTsExtensions' is enabled.Aynı projeden "type": "module" satırını kaldırınca tsc aynı kaynak koddan CommonJS üretti:
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const matematik_js_1 = require("./matematik.js");
console.log((0, matematik_js_1.topla)(2, 3));Yani nodenext yalnızca ESM üreten bir mod değildir; Reference belgesinin de vurguladığı gibi her dosyanın algılanan biçimine göre ESM veya CommonJS üretir. Belge, Node.js'te çalışacak uygulama ve kütüphaneler için doğru module değerlerinin yalnızca node16, node18, node20 ve nodenext olduğunu söyler.
node16, node18, node20 ve nodenext farkı
Sabit sürümlü modlar ilgili Node.js sürümündeki davranışı dondurur, nodenext ise en güncel Node.js davranışını izler. Reference belgesinin tablosu ve 5.8/5.9 sürüm notlarına göre (node20 satırındaki çözümleme modunu ve import attributes desteğini tsc 6.0 ile ayrıca denedik):
| module | Varsayılan target | moduleResolution | Import attributes | require(esm) |
|---|---|---|---|---|
| node16 | es2022 | node16 | Hayır | Hayır |
| node18 | es2022 | node16 | Evet | Hayır |
| node20 | es2023 | node16 | Evet | Evet |
| nodenext | esnext | nodenext | Evet | Evet |
module ile moduleResolution Node modlarında birlikte gider. module değerini nodenext yapıp moduleResolution değerine bundler yazdığımızda iki hata aldık:
error TS5095: Option 'bundler' can only be used when 'module' is set to 'preserve', 'commonjs', or 'es2015' or later.
error TS5109: Option 'moduleResolution' must be set to 'NodeNext' (or left unspecified) when option 'module' is set to 'NodeNext'.Node.js tarafındaki kurulum, @types/node ve çalıştırma seçenekleri için TypeScript ile Node.js yazısına, Node.js'in kendisi için Node.js nedir yazısına bakabilirsiniz.
Bundler kullananlar için: moduleResolution bundler
bundler modu, bundler'ların çoğunun uyguladığı karma kuralları modeller: uzantısız göreli yollar ve klasör index dosyaları kabul edilir, package.json içindeki exports ve imports alanları da okunur. Choosing Compiler Options rehberindeki modül ayarlarının kısaltılmış hâli:
{
"compilerOptions": {
"module": "esnext",
"moduleResolution": "bundler",
"noEmit": true,
"allowImportingTsExtensions": true,
"verbatimModuleSyntax": true
}
}Bu ayarlarla import { topla } from "./matematik"; ve "./matematik.ts" yazımları hatasız derlendi. allowImportingTsExtensions yalnızca noEmit veya emitDeclarationOnly açıkken kullanılabilir, çünkü bu yollar çıktı JavaScript'te çözülemez. TypeScript 6.0 ayrıca bundler çözümlemesinin "module": "commonjs" ile birlikte kullanılmasına izin verdi; sürüm notları bunu node10'dan çıkış için bir ara yol olarak anlatır.
verbatimModuleSyntax: ne yazarsanız o çıkar
verbatimModuleSyntax açıkken type belirteci olmayan her import korunur, type belirteci olanlar tamamen silinir. Bu, dosyanın gerçek biçimiyle uyumsuz sözdizimini görünür kılar. CommonJS olarak algılanan bir projede ve tip import'larında tsc 6.0'ın verdiği hatalar:
// "type": "module" olmayan projede, CommonJS olarak algılanan main.ts:
import { topla } from "./matematik.js";
// TS1295: ECMAScript imports and exports cannot be written in a CommonJS file under 'verbatimModuleSyntax'.
// Adjust the 'type' field in the nearest 'package.json' to make this file an ECMAScript module, ...
// ESM projede bir interface'i normal import ile almak:
import { Kullanici } from "./tip.js";
// TS1484: 'Kullanici' is a type and must be imported using a type-only import when 'verbatimModuleSyntax' is enabled.
// Doğrusu:
import type { Kullanici } from "./tip.js";Kütüphane yazıyorsanız
Choosing Compiler Options rehberi kütüphaneler için "module": "node18" ile birlikte strict, verbatimModuleSyntax ve declaration önerir. Gerekçe şudur: bundler çözümlemesi export * from "./utils" gibi yalnızca bundler'da çalışan kodu kabul eder; bu kod npm'e yayınlandığında Node.js kullanıcısı ERR_MODULE_NOT_FOUND alır. "./utils.js" şeklinde yazılan kod ise hem Node.js'te hem bundler'larda çalışır. Tip bildirim dosyalarının üretimi için declaration files yazısına bakın.
Sık yapılan hatalar

- Node.js projesinde
"module": "esnext"veya"commonjs"kullanmak. Theory belgesine göre çıktı aynı görünse bile tip denetimi farklı olabilir. - ESM projede göreli import'lara uzantı yazmamak (TS2835) veya
.tsuzantısı yazmak (TS5097). "type": "module"eklemeyi unutup ESM beklerken CommonJS çıktısı almak.moduleResolution: nodeayarını 6.0'a geçerken bırakmak (TS5107).- Yol takma adları için
baseUrl'e güvenmek; 6.0'da bu da kullanımdan kaldırıldı. Ayrıntılar paths ayarları yazısında.
Sık Sorulan Sorular
Import yolunda neden .ts değil .js yazıyorum?
Çünkü TypeScript yolu değiştirmeden çıktıya kopyalar ve çalışma anında var olan dosya .js dosyasıdır. Derleyici .js yolunu tip bilgisi için kaynak .ts dosyasına kendisi eşler.
nodenext mi node20 mi seçmeliyim?
5.8 sürüm notları Node.js 22 ve üstü kullananlara nodenext'i önerir. node20 (TypeScript 5.9) gelecekte davranışı değişmeyecek sabit bir seçenektir ve target değerini es2023 olarak varsayar; belirli bir Node.js sürümüne sabitlenmek istiyorsanız uygundur.
Vite veya esbuild kullanıyorum, hangi ayar?
Kaynak dosyaları bundler işliyorsa "module": "esnext" veya "preserve" ile "moduleResolution": "bundler" ve noEmit kullanın. Reference belgesi, ham .ts dosyalarını bir araç işlediğinde preserve'ün en iyi seçim olduğunu belirtir.
CommonJS bir dosyadan ESM paket require edebilir miyim?
nodenext modunda TypeScript buna izin verir; Reference belgesine göre bu Node.js 22.12.0 ve sonrasının davranışını yansıtır. Modül veya bağımlılıkları üst düzey await kullanıyorsa Node.js hata verir ve TypeScript bunu derleme sırasında yakalamaz. node16 ve node18 modlarında bu kullanım hatadır.
Marka adları sahiplerine aittir. Bu yazı bağımsız bir teknik rehberdir; adı geçen kuruluşlarla bayilik veya ortaklık ilişkisi bulunduğu anlamına gelmez.
İlgili içerikler: TypeScript öğrenme rehberi · JavaScript ES modülleri · tsconfig.json rehberi · TypeScript ile Node.js · paths ve alias ayarları · TypeScript 6.0 yenilikleri