JavaScript and TypeScript course Β· Module 6: TypeScript Basics
TypeScript Compiler (tsc)
In this lesson13
Introduction: The InGen laboratory
Welcome to the InGen genetic laboratory! Just as the park's scientists transform ancient DNA sequences into living dinosaurs, the TypeScript compiler transforms TypeScript code into standard JavaScript that can run in a browser or Node.js environment.
Dr. Wu, the park's chief geneticist, often says: "We give life to code from millions of years ago." Similarly, the TypeScript compiler lets us write code in a modern language that is then transformed into a more "primitive" form of JavaScript, understandable by all environments.
What is the TypeScript compiler?
The TypeScript compiler (usually called tsc - TypeScript Compiler) is a tool that analyzes your TypeScript code, checks types, and then generates corresponding JavaScript code. It is a bridge between the world of statically typed TypeScript and dynamically typed JavaScript.
In Jurassic Park terminology, we can say that:
- TypeScript code is like isolated DNA sequences of a dinosaur
- The compilation process is like the cloning procedure
- The generated JavaScript code is the living dinosaur, ready to be released into the park
Basics of using the tsc compiler
Installing the compiler
Before we start genetic experiments, we need the right equipment:
1# Global installation (gives access to the tsc command system-wide)
2npm install -g typescript
3
4# Local installation (only within the project)
5npm install --save-dev typescriptCompiling a single file
Compiling a single TypeScript file is like creating a single dinosaur in the laboratory:
1# Syntax: tsc [filename].ts
2tsc security-system.tsAfter running this command, a JavaScript file with the same name will be created: security-system.js.
Compiling an entire project
In a real Jurassic Park we don't create individual dinosaurs - we build an entire ecosystem. Similarly, in larger projects we compile many files at once:
1# Compile the entire project according to tsconfig.json
2tsc
3
4# Compile with watch mode - the compiler will watch for changes and recompile automatically
5tsc --watchThe compilation process
The TypeScript compilation process proceeds in several steps, similar to the dinosaur creation process in the laboratory:
- Scanning - the compiler analyzes all source files and their dependencies
- Parsing - transforms source code into an Abstract Syntax Tree (AST)
- Type checking - verifies that types are consistent and issues warnings/errors
- Transformations - transforms the AST into appropriate JavaScript structures
- Emission - generates JavaScript files, source maps, and type declaration files
This process can be compared to the stages of creating a dinosaur:
- Scanning is collecting DNA samples from various sources
- Parsing is DNA sequencing
- Type checking is verifying that the sequences are correct and compatible
- Transformations are genetic modifications to make the DNA work in a modern environment
- Emission is placing the finished genetic code in a dinosaur egg
Most important command-line options
The TypeScript compiler offers many command-line options that allow for precise control of the compilation process:
Options for output file types
1# Specifying the output directory
2tsc --outDir ./dist
3
4# Generating type declaration files (.d.ts)
5tsc --declaration
6
7# Generating source maps (.js.map) for easier debugging
8tsc --sourceMap
9
10# Merging multiple output files into one (deprecated for ES modules)
11tsc --outFile ./dist/bundle.jsOptions controlling the compilation process
1# Compile without emitting files (type checking only)
2tsc --noEmit
3
4# Compile despite errors
5tsc --noEmitOnError false
6
7# Enable strict mode
8tsc --strict
9
10# Compile in watch mode (automatic recompilation on changes)
11tsc --watchOptions affecting generated code
1# Specifying the target JavaScript version (ES5, ES6, etc.)
2tsc --target ES2015
3
4# Specifying the module system (commonjs, amd, system, esm, etc.)
5tsc --module commonjs
6
7# Preserving directory structure
8tsc --rootDir ./srcDiagnostic options
1# Displaying detailed information about the compilation process
2tsc --verbose
3
4# Listing all files that are part of the compilation
5tsc --listFiles
6
7# Displaying the resulting configuration
8tsc --showConfigHow does TypeScript compile different code constructs?
Let's see how the compiler transforms specific TypeScript constructs to JavaScript:
1. Interfaces and types - disappear during compilation
1// TypeScript code (security-types.ts)
2interface Employee {
3 id: number;
4 name: string;
5 role: string;
6 accessLevel: number;
7}
8
9type AccessLevel = 1 | 2 | 3 | 4 | 5;
10
11function checkAccess(employee: Employee, requiredLevel: AccessLevel): boolean {
12 return employee.accessLevel >= requiredLevel;
13}1// Compiled JavaScript (security-types.js)
2function checkAccess(employee, requiredLevel) {
3 return employee.accessLevel >= requiredLevel;
4}Interfaces and types are used only during type checking and are completely removed from JavaScript code. It's like dinosaur DNA - important during creation, but invisible in the final creature.
2. Type annotations - also removed
1// TypeScript code (employee.ts)
2function createEmployee(name: string, role: string, accessLevel: number): Employee {
3 return {
4 id: generateId(),
5 name,
6 role,
7 accessLevel
8 };
9}
10
11let newEmployee: Employee;1// Compiled JavaScript (employee.js)
2function createEmployee(name, role, accessLevel) {
3 return {
4 id: generateId(),
5 name,
6 role,
7 accessLevel
8 };
9}
10
11let newEmployee;Type annotations disappear, but the code structure remains the same. It's like a genetic map used to create a dinosaur, but not transferred to the final creature.
3. Advanced TypeScript features that require transformation
1// TypeScript code (tracking-system.ts)
2// Using optional chaining and nullish coalescing operator
3function getLocationName(dinosaur?: Dinosaur) {
4 return dinosaur?.currentLocation?.name ?? "Unknown Location";
5}
6
7// Using rest parameters and destructuring
8function analyzeDinosaurs(...dinosaurs: Dinosaur[]) {
9 const [mostDangerous, ...others] = dinosaurs.sort((a, b) => b.dangerLevel - a.dangerLevel);
10 return { mostDangerous, others };
11}Compilation may look different depending on the target ES version. For ES5 it might look like this:
1// Compiled JavaScript (tracking-system.js) for ES5
2function getLocationName(dinosaur) {
3 var _a, _b;
4 return (_b = (_a = dinosaur === null || dinosaur === void 0 ? void 0 : dinosaur.currentLocation) === null || _a === void 0 ? void 0 : _a.name) !== null && _b !== void 0 ? _b : "Unknown Location";
5}
6
7function analyzeDinosaurs() {
8 var dinosaurs = [];
9 for (var _i = 0; _i < arguments.length; _i++) {
10 dinosaurs[_i] = arguments[_i];
11 }
12 var sortedDinosaurs = dinosaurs.sort(function (a, b) { return b.dangerLevel - a.dangerLevel; });
13 var mostDangerous = sortedDinosaurs[0], others = sortedDinosaurs.slice(1);
14 return { mostDangerous: mostDangerous, others: others };
15}Here the compiler had to do much more work to transform modern JavaScript features into ES5-compatible code. It's like adapting "primitive" genetic code to work in a modern environment.
4. TypeScript classes
1// TypeScript code (dinosaur.ts)
2class Dinosaur {
3 private _healthStatus: number = 100;
4
5 constructor(
6 public readonly species: string,
7 public age: number,
8 private readonly dangerLevel: number
9 ) {}
10
11 get health(): number {
12 return this._healthStatus;
13 }
14
15 feed(amount: number): void {
16 this._healthStatus = Math.min(100, this._healthStatus + amount);
17 console.log(`${this.species} has been fed. New health: ${this._healthStatus}%`);
18 }
19}1// Compiled JavaScript (dinosaur.js) for ES2015
2class Dinosaur {
3 constructor(species, age, dangerLevel) {
4 this.species = species;
5 this.age = age;
6 this.dangerLevel = dangerLevel;
7 this._healthStatus = 100;
8 }
9
10 get health() {
11 return this._healthStatus;
12 }
13
14 feed(amount) {
15 this._healthStatus = Math.min(100, this._healthStatus + amount);
16 console.log(`${this.species} has been fed. New health: ${this._healthStatus}%`);
17 }
18}For ES5, classes will be transformed into constructor functions and prototypes.
Type declaration files (.d.ts)
In the InGen laboratory, detailed documentation is kept for all created species. In the TypeScript world, the equivalent of such documentation is type declaration files (.d.ts).
These files contain only type information, without implementation. They are used by IDEs and the compiler to provide code hints and type checking.
1// dinosaur.d.ts - type declaration file for the Dinosaur class
2declare class Dinosaur {
3 readonly species: string;
4 age: number;
5 private readonly dangerLevel: number;
6 private _healthStatus: number;
7
8 constructor(species: string, age: number, dangerLevel: number);
9
10 get health(): number;
11 feed(amount: number): void;
12}To generate type declaration files for your project, you can use the --declaration option:
1tsc --declarationSource maps
Debugging dinosaurs can be complicated - we don't always know which DNA sequence corresponds to a given behavior. Similarly, debugging compiled JavaScript code can be difficult without source maps.
Source maps are .js.map` files that allow the browser or Node.js environment to map compiled JavaScript code back to the original TypeScript code. This allows you to debug TypeScript code directly, even when JavaScript is running.
To generate source maps, use the --sourceMap option:
1tsc --sourceMapProjects (tsconfig.json)
In a large park full of different dinosaur species, we need detailed plans and specifications. Similarly, in larger TypeScript projects we use the tsconfig.json file to configure the compiler.
This file allows you to set all compiler options in one place, which is much more convenient than passing them every time on the command line.
1# Creating a basic tsconfig.json file
2tsc --init
3
4# Compiling the project according to the configuration
5tscSuppressing errors and gradual migration
Dr. Wu sometimes has to ignore certain genetic incompatibilities so that a dinosaur can survive. Similarly, when migrating an existing JavaScript project to TypeScript, we may need to temporarily ignore some type errors.
Ignoring errors in specific lines
1// @ts-ignore
2element.style.background = 'red'; // TypeScript would report an error, but we ignore it
3
4// @ts-expect-error
5console.log(dinosaur.location); // We document that we expect an error hereTemporary use of the any type
1function legacyFunction(data: any) {
2 // We temporarily use 'any', but plan to fix this later
3 return data.process();
4}Gradually enabling type checking
We can also gradually enable type checking throughout the project, starting with less strict settings:
1// tsconfig.json with less strict settings
2{
3 "compilerOptions": {
4 "allowJs": true, // Allows compiling .js files
5 "checkJs": false, // Doesn't check types in .js files
6 "noImplicitAny": false, // Allows implicit 'any' type
7 "strictNullChecks": false // Doesn't require checking null/undefined
8 }
9}Over time, as the project becomes more "tamed", we can gradually increase the strictness of type checking.
Common compiler problems and their solutions
1. TypeScript version conflict
Problem: A global TypeScript installation may conflict with the project's local version.
Solution: Use the locally installed compiler via npx:
1npx tsc2. Incorrect paths
Problem: The compiler can't find files or compiles the wrong files.
Solution: Check the include, exclude, rootDir and outDir settings in tsconfig.json:
1{
2 "compilerOptions": {
3 "rootDir": "./src",
4 "outDir": "./dist"
5 },
6 "include": ["src/**/*"],
7 "exclude": ["node_modules", "**/*.spec.ts"]
8}3. Type incompatibilities with libraries
Problem: TypeScript reports errors about types in external libraries.
Solution: Install the appropriate type definition files or create your own:
1npm install --save-dev @types/libraryOr create your own definition file:
1// types/missing-library.d.ts
2declare module 'missing-library' {
3 export function someFunction(): void;
4}4. Errors in complex generic types
Problem: TypeScript has problems with inferred types in complex generic structures.
Solution: Provide explicit type annotations at strategic locations:
1// Instead of letting TypeScript infer the type:
2const result = complexFunction(data);
3
4// Provide an explicit type annotation:
5const result: ExpectedReturnType = complexFunction(data);Advanced usage: compiler API
For the most advanced scenarios, TypeScript provides a compilation API that allows deep integration with developer tools. It's like access to advanced laboratory tools for particularly demanding genetic experiments.
1import * as ts from 'typescript';
2
3// We create a compiler host
4const host = ts.createCompilerHost({});
5
6// We create a TypeScript program
7const program = ts.createProgram(['file1.ts', 'file2.ts'], {
8 target: ts.ScriptTarget.ES2015,
9 module: ts.ModuleKind.CommonJS
10}, host);
11
12// We compile the program
13const emitResult = program.emit();
14
15// We get the diagnostics (errors and warnings)
16const diagnostics = ts.getPreEmitDiagnostics(program).concat(emitResult.diagnostics);
17
18// We display the diagnostics
19diagnostics.forEach(diagnostic => {
20 if (diagnostic.file) {
21 const { line, character } = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start!);
22 const message = ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n');
23 console.log(`${diagnostic.file.fileName} (${line + 1},${character + 1}): ${message}`);
24 } else {
25 console.log(ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n'));
26 }
27});This functionality is used by tools such as webpack, Rollup, or ESBuild to integrate TypeScript compilation into their own build processes.
Summary
The TypeScript compiler, like the InGen genetic laboratory, transforms advanced, safe code (TypeScript) into a form that can be "brought to life" in a browser or Node.js environment (JavaScript).
Key points:
The TypeScript compiler (
tsc) transforms TypeScript code into JavaScript, removing type annotations and transforming advanced features.The compilation process includes: scanning, parsing, type checking, transformations and emission.
There are many compiler options that can be passed on the command line or configured in
tsconfig.json.Every TypeScript feature has a way of compiling to JavaScript, with the complexity of this compilation depending on the target JavaScript version.
.d.tsfiles and source maps.js.maphelp with documentation and debugging.When migrating existing projects, TypeScript allows gradual introduction of types.
For advanced scenarios, there is a TypeScript compilation API.
Just as the InGen laboratory needs precise protocols and tools to create dinosaurs, programmers need a well-configured TypeScript compiler to create safe and efficient JavaScript applications.
In the next lesson we'll dive into the basic types available in TypeScript - it will be like studying different dinosaur species in our park!
Code for this lesson: index.ts
1// TypeScript Compiler - InGen Laboratory
2console.log("The TypeScript compiler in action!\n");
3
4// ===========================================
5// 1. Compilation basics
6// ===========================================
7console.log("=== COMPILATION BASICS ===");
8console.log("TypeScript -> tsc -> JavaScript\n");
9
10// This TypeScript code will be compiled to JavaScript
11interface Dinosaur {
12 species: string;
13 period: 'Triassic' | 'Jurassic' | 'Cretaceous';
14 diet: 'carnivore' | 'herbivore' | 'omnivore';
15 weight: number;
16}
17
18const trex: Dinosaur = {
19 species: "Tyrannosaurus Rex",
20 period: 'Cretaceous',
21 diet: 'carnivore',
22 weight: 8000
23};
24
25console.log("Dinosaur data:", trex);
26
27// ===========================================
28// 2. Compilation with type checking
29// ===========================================
30console.log("\n=== TYPE CHECKING ===");
31
32function calculateFeedAmount(dino: Dinosaur): number {
33 // Predators eat 5% of their weight daily
34 // Herbivores eat 10% of their weight daily
35 const percentage = dino.diet === 'carnivore' ? 0.05 : 0.10;
36 return dino.weight * percentage;
37}
38
39const feedAmount = calculateFeedAmount(trex);
40console.log(`Daily feed for ${trex.species}: ${feedAmount}kg`);
41
42// ===========================================
43// 3. Target ES version
44// ===========================================
45console.log("\n=== TARGET ES VERSION ===");
46
47// Arrow functions (ES6+)
48const getDinosaurs = (): Dinosaur[] => [trex];
49
50// Template literals (ES6+)
51const description = `${trex.species} lived in ${trex.period} period`;
52console.log(description);
53
54// Optional chaining (ES2020+)
55interface Park {
56 dinosaurs?: Dinosaur[];
57}
58
59const park: Park = { dinosaurs: getDinosaurs() };
60const firstDino = park.dinosaurs?.[0];
61console.log("First dinosaur:", firstDino?.species);
62
63// ===========================================
64// 4. Modules
65// ===========================================
66console.log("\n=== MODULES ===");
67
68// Export/Import (ES6 modules)
69export class DinosaurManager {
70 private dinosaurs: Dinosaur[] = [];
71
72 add(dino: Dinosaur): void {
73 this.dinosaurs.push(dino);
74 console.log(`Added ${dino.species} to collection`);
75 }
76
77 getAll(): Dinosaur[] {
78 return [...this.dinosaurs];
79 }
80
81 findByDiet(diet: Dinosaur['diet']): Dinosaur[] {
82 return this.dinosaurs.filter(d => d.diet === diet);
83 }
84}
85
86const manager = new DinosaurManager();
87manager.add(trex);
88console.log("Total dinosaurs:", manager.getAll().length);
89
90// ===========================================
91// 5. File generation
92// ===========================================
93console.log("\n=== GENERATED FILES ===");
94console.log("JavaScript (.js) - executable code");
95console.log("Source Maps (.js.map) - mapping back to TS");
96console.log("Declaration Files (.d.ts) - type definitions");
97
98console.log("\nThe TypeScript compiler is ready to work!");Spotted a mistake in this lesson?
Check yourself
Answer the questions from this lesson. Pick an answer to see right away whether it is correct.
1. What command runs the TypeScript compiler?
2. What does the 'strict: true' option in tsconfig.json do?
Hands-on tasks in the game
- Code editor
Define a function with parameter types and check for compilation errors.
- Click in order
Arrange the TypeScript compilation command with the output directory:
- Vertical ordering
Arrange the steps of the TypeScript compilation process: