Why TypeScript?
TypeScript is JavaScript with types. That sounds simple, but it fundamentally changes how you write code and find errors.
The Problem with JavaScript:
function calculateTotal(items) {
return items.reduce((sum, item) => sum + item.price, 0);
}
// Works
calculateTotal([{ price: 10 }, { price: 20 }]); // 30
// Runtime crash!
calculateTotal("not an array"); // TypeError
calculateTotal([{ cost: 10 }]); // NaN (price is undefined)You only find these errors when the code runs – worst case in production.
The TypeScript Solution:
interface Item {
price: number;
}
function calculateTotal(items: Item[]): number {
return items.reduce((sum, item) => sum + item.price, 0);
}
// Error shown immediately!
calculateTotal("not an array"); // Type 'string' is not assignable
calculateTotal([{ cost: 10 }]); // Property 'price' is missingThe editor shows errors before you run the code.
The Basics in 5 Minutes
1. Primitive Types
// Basic types
let name: string = "Max";
let age: number = 30;
let isActive: boolean = true;
// Arrays
let numbers: number[] = [1, 2, 3];
let names: string[] = ["Anna", "Ben"];
// TypeScript often infers automatically
let city = "Stuttgart"; // TypeScript knows: this is a string2. Objects and Interfaces
// Interface defines the shape of an object
interface User {
id: number;
name: string;
email: string;
age?: number; // Optional (?)
}
const user: User = {
id: 1,
name: "Max Mustermann",
email: "max@example.com",
// age is optional, can be omitted
};
// Function with typed parameter
function greetUser(user: User): string {
return `Hello, ${user.name}!`;
}3. Functions
// Parameters and return type
function add(a: number, b: number): number {
return a + b;
}
// Arrow Function
const multiply = (a: number, b: number): number => a * b;
// Optional parameters
function greet(name: string, greeting?: string): string {
return `${greeting || "Hello"}, ${name}!`;
}
// Default values
function createUser(name: string, role: string = "user"): User {
// ...
}4. Union Types
// Can have multiple types
let id: string | number;
id = "abc123"; // OK
id = 42; // Also OK
// Useful for functions
function formatId(id: string | number): string {
if (typeof id === "string") {
return id.toUpperCase();
}
return id.toString();
}5. Type Aliases
// Define custom types
type Status = "pending" | "approved" | "rejected";
interface Order {
id: number;
status: Status;
}
const order: Order = {
id: 1,
status: "pending", // Only these 3 values allowed
};
order.status = "invalid"; // Error!Practical Patterns
Typing API Responses
interface ApiResponse<T> {
data: T;
status: number;
message: string;
}
interface Product {
id: number;
name: string;
price: number;
}
async function fetchProducts(): Promise<ApiResponse<Product[]>> {
const response = await fetch("/api/products");
return response.json();
}
// Usage - TypeScript knows the structure
const result = await fetchProducts();
result.data.forEach(product => {
console.log(product.name); // Autocomplete works!
});React Components
interface ButtonProps {
label: string;
onClick: () => void;
variant?: "primary" | "secondary";
disabled?: boolean;
}
function Button({ label, onClick, variant = "primary", disabled }: ButtonProps) {
return (
<button
onClick={onClick}
disabled={disabled}
className={variant}
>
{label}
</button>
);
}
// Usage - errors shown immediately
<Button label="Click me" onClick={() => {}} />
<Button label={42} /> // Error: number is not a stringMigration from JavaScript
Step 1: Setup
npm install typescript @types/node --save-dev
npx tsc --initStep 2: Migrate Gradually
Rename files from .js to .ts (or .tsx for React). TypeScript allows any initially:
// Before (JavaScript)
function processData(data) {
return data.map(item => item.value);
}
// Intermediate step (TypeScript with any)
function processData(data: any): any {
return data.map((item: any) => item.value);
}
// Final (fully typed)
interface DataItem {
value: number;
}
function processData(data: DataItem[]): number[] {
return data.map(item => item.value);
}Step 3: Enable Strict Mode
In tsconfig.json:
{
"compilerOptions": {
"strict": true
}
}Common Pitfalls
1. Object vs. object vs. {}
// Wrong - too general
let data: Object = { name: "Max" };
// Right - specific
interface UserData {
name: string;
}
let data: UserData = { name: "Max" };2. Use Type Assertions Sparingly
// Avoid when possible
const element = document.getElementById("app") as HTMLDivElement;
// Better: Type Guard
const element = document.getElementById("app");
if (element instanceof HTMLDivElement) {
// Now TypeScript knows it's an HTMLDivElement
}3. null and undefined
function getUser(id: number): User | null {
// Can return User or null
}
const user = getUser(1);
console.log(user.name); // Error! user could be null
// Correct:
if (user) {
console.log(user.name);
}
// Or with Optional Chaining:
console.log(user?.name);Conclusion
TypeScript isn't a silver bullet, but it solves real problems:
- Fewer bugs: Many errors are found while writing, not in production
- Better IDE support: Autocomplete, refactoring, navigation
- Documentation in code: Types explain what a function expects
- Safer refactoring: The compiler finds all places that need adjustment
Getting started takes some time, but the ROI comes quickly – especially in larger projects or teams.