This episode covers the final result of TypeScript compilation: target and module settings, outDir for output location, source maps for debugging, type declarations and declaration maps, and the role of bundlers like tsup and esbuild in production.

TypeScript code must be turned into JavaScript before it can run. Episode 20 covers what happens during that process: how tsc translates code, where the result is placed, and how it stays debuggable even after being transformed.
A controlled build produces predictable artifacts. The runtime target determines the generated JavaScript syntax. Modules and bundlers determine the distribution shape. Source maps ensure production errors still point at the original TypeScript code, not at the compiled JavaScript.
Episode 20 dissects the main build options, the role of source maps, type declarations for library consumers, and how bundlers fit into production.
The basic build setup starts in tsconfig:
{
"compilerOptions": {
"target": "ES2022",
"module": "NodeNext",
"outDir": "dist",
"rootDir": "src"
}
}The target option determines the ECMAScript version of the output, for example ES2022. The module option determines the JavaScript module format. outDir places the compiled result, and rootDir limits the input structure so the folder layout in dist mirrors src. Running tsc and then deploying the contents of dist is the most basic and easiest-to-understand pattern.
The lib option determines the set of runtime APIs the compiler knows, for example ES2022 for language features and DOM for browser environments. Choosing the right lib prevents using APIs that don't exist in the target. target and lib must be chosen together so the output doesn't use features beyond the runtime's reach.
Info
If the runtime target is older than the features you use, tsc lowers the syntax, but extra APIs like Array.findLast still need the matching lib. For this case consider a polyfill or raising the target when possible.
Source maps connect the output to the original code:
{
"compilerOptions": {
"sourceMap": true,
"sourceRoot": "../src"
}
}With sourceMap: true, tsc generates a .map file next to every output file. Stack traces in production can be mapped back to the original TypeScript file and line, so debugging doesn't guess at transformed JavaScript. The sourceRoot option points to the source location in the map.
During development, source maps help stack traces in editors and runners like tsx. In production, maps can be uploaded to error tracking services like Sentry to find the original line of every incident. Choosing to keep or discard maps is a trade-off between debugging convenience and code secrecy.
Info
Source maps can expose the structure of your code. For internal applications, leave them on. For tightly guarded commercial libraries, consider removing maps at distribution.
When building a library, type output is as important as code output:
{
"compilerOptions": {
"declaration": true,
"declarationMap": true,
"declarationDir": "dist/types"
}
}The declaration: true option generates a .d.ts file for every module. Library consumers writing TypeScript use these declarations to get types. declarationMap links declarations back to the source code, so the editor can jump to the original definition when pressing go-to-definition.
For modern frontend and backend applications, a bundler replaces tsc for runtime output:
bunx tsup src/index.ts --format esm --dtsThe bunx tsup command uses esbuild to combine code and generate type declarations at once. Bundlers resolve imports, eliminate dead code, and produce optimized output. Frameworks like Vite and Next.js use similar bundlers behind the scenes.
When building a full application, the bundler also handles assets like CSS and images, splits code into chunks, and applies optimizations like minification. Tsc does none of this; tsc only produces one file per module. That's why modern applications almost always use a bundler as the final build stage.
tsc --project tsconfig.build.json
bunx tsup src/index.ts --format esm --dtsA common division of labor:
Tip
tsc is used for type checking and generating .d.ts declarations, while the bundler is responsible for the optimized runtime JavaScript. This split has become the standard in many modern toolchains.
Episode 20 puts the final compilation result under your control: target, module, and outDir settings determine the output shape; source maps keep debugging on track; declarations serve library consumers; and bundlers polish production artifacts.
Key takeaways:
target, module, outDir, and rootDir shape tsc's output.declaration: true generates .d.ts for library consumers.declarationMap links declarations to the original source.tsc for types and declarations; bundler for runtime JavaScript.In the next episode 21 we'll discuss compilation performance and incremental builds — speeding up tsc on ever-growing projects.