Introduction to TypeScript
What is TypeScript?
TypeScript is a statically typed superset of JavaScript developed by Microsoft. It adds optional type annotations, interfaces, and advanced type system features to JavaScript, then compiles down to plain JavaScript that runs anywhere.
Core Benefits
- Compile-time error detection: Catch bugs before runtime
- Better IDE support: Autocomplete, refactoring, and navigation
- Self-documenting code: Types serve as living documentation
- Safer refactoring: The compiler catches breakage across large codebases
TypeScript vs JavaScript
// JavaScript - no error at compile time
function add(a, b) {
return a + b;
}
add('1', 2); // '12' - string concatenation, not addition
// TypeScript - compile error: Argument of type 'string' is not assignable to number
function addTS(a: number, b: number): number {
return a + b;
}
addTS('1', 2); // Type error caught at compile time
How TypeScript Works
TypeScript code goes through a compilation step:
- Source code (
.tsfiles) is written with type annotations - Type checker validates types and catches errors
- Compiler strips type annotations and outputs
.jsfiles - JavaScript runs in the browser, Node.js, or any JS runtime
TypeScript does not add runtime behavior—types exist only during development and are erased during compilation.
Installation and Setup
Installing TypeScript
Global Installation
npm install -g typescript
# Verify installation
tsc --version
# Version 5.x.x
Local Installation (Recommended)
# Initialize a Node.js project
npm init -y
# Install TypeScript as a dev dependency
npm install --save-dev typescript
# Install type definitions for Node.js
npm install --save-dev @types/node
# Add tsc to package.json scripts
npm pkg set scripts.build="tsc"
npm pkg set scripts.watch="tsc --watch"
Project Structure
my-ts-project/
├── src/
│ ├── index.ts
│ ├── utils.ts
│ └── types/
│ └── index.ts
├── dist/ # compiled output
├── tsconfig.json
├── package.json
└── package-lock.json
Running TypeScript
# Compile once
npx tsc
# Watch mode - recompiles on file changes
npx tsc --watch
# Run a single file with ts-node (install separately)
npx ts-node src/index.ts
The @types/node package provides type definitions for Node.js built-in modules like fs, path, and http. Without it, TypeScript would not know the types for Node.js APIs.
tsconfig.json Deep Dive
tsconfig.json Configuration
The tsconfig.json file tells the TypeScript compiler how to compile your project.
Minimal Configuration
{
"compilerOptions": {
"target": "ES2022",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}
Key Compiler Options
| Option | Description | Recommended Value |
|---|---|---|
target |
ECMAScript version for output | ES2022 |
module |
Module system used | NodeNext or ESNext |
strict |
Enable all strict checks | true |
outDir |
Output directory for .js files |
./dist |
rootDir |
Root directory of source files | ./src |
esModuleInterop |
Allow default imports from CommonJS | true |
declaration |
Generate .d.ts declaration files |
true |
sourceMap |
Generate source maps for debugging | true |
Strict Mode Breakdown
When strict: true is enabled, it activates:
strictNullChecks-nullandundefinedare distinct typesnoImplicitAny- Error on variables with implicitanytypenoImplicitThis- Error onthiswith implicitanytypestrictFunctionTypes- Stricter function type checkingstrictBindCallApply- Stricterbind,call,applycheckingstrictPropertyInitialization- Class properties must be initialized
Include and Exclude Patterns
{
"include": ["src/**/*", "tests/**/*"],
"exclude": ["node_modules", "dist", "**/*.spec.ts"]
}
The include and exclude arrays use glob patterns to specify which files the compiler should process. Files not matching these patterns are not type-checked.
Compiler Options in Practice
Compiler Options in Practice
Target and Module Resolution
{
"compilerOptions": {
"target": "ES2022",
"module": "NodeNext",
"moduleResolution": "NodeNext"
}
}
The target determines which JavaScript features are downlevel compiled. ES2022 supports top-level await, class fields, and the using keyword natively.
The module and moduleResolution settings must match. NodeNext is the modern standard for Node.js projects.
Declaration Files
{
"compilerOptions": {
"declaration": true,
"declarationDir": "./dist/types",
"emitDeclarationOnly": false
}
}
Declaration files (.d.ts) allow other TypeScript projects to use your library with full type information.
Path Aliases
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["src/*"],
"@types/*": ["src/types/*"]
}
}
}
This enables clean imports like import { User } from '@/types/user' instead of relative paths.
Multiple tsconfig Files
// tsconfig.base.json
{
"compilerOptions": {
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true
}
}
// tsconfig.json
{
"extends": "./tsconfig.base.json",
"compilerOptions": {
"target": "ES2022",
"module": "NodeNext",
"outDir": "./dist",
"rootDir": "./src"
},
"include": ["src/**/*"]
}
Extending a base config keeps shared settings in one place and allows different configs for build vs test.
Best Practices
Best Practices and Common Mistakes
Do's
// Use strict mode - always
tsc --strict
// Use explicit return types for exported functions
export function processData(input: string): Result {
// ...
}
// Use @types packages for third-party libraries
npm install --save-dev @types/express
Don'ts
// Don't use 'any' as a shortcut
data: any; // Bad
// Don't ignore compiler errors with @ts-ignore
// @ts-ignore
someRiskyCode(); // Bad - hides real issues
// Don't mix CommonJS and ES modules without interop
tsc --esModuleInterop // Good - enables seamless mixing
Common Setup Mistakes
| Mistake | Fix |
|---|---|
Missing @types/node |
npm install --save-dev @types/node |
Forgetting esModuleInterop |
Add to tsconfig.json |
Not using strict: true |
Enable it from the start |
Wrong moduleResolution |
Match with module setting |
Not excluding dist |
Add to exclude array |
Verifying Your Setup
# Check for type errors without emitting files
npx tsc --noEmit
# See the full config that TypeScript resolves
npx tsc --showConfig
# List all files that would be compiled
npx tsc --listFiles
Always run tsc --noEmit in your CI pipeline to catch type errors before deployment.