TypeScript for Beginners: Why Use Types?
TypeScript is JavaScript with types. That's it. If you know JavaScript, you already know most of TypeScript. The types are optional annotations that help you catch errors early and understand your code better.
The Problem TypeScript Solves
JavaScript is dynamically typed. Variables can hold any value at any time:
let message = "hello";
message = 42; // Valid JavaScript
message = { x: 1 }; // Also valid
This flexibility is convenient, but it causes problems:
function greet(user) {
return "Hello, " + user.name;
}
greet({ name: "Alice" }); // Works
greet(null); // Runtime error: Cannot read property 'name' of null
greet("Bob"); // Returns "Hello, undefined" — probably a bug
These errors only appear when the code runs. In a large app, they hide until a user hits the wrong code path in production.
How TypeScript Helps
TypeScript catches these errors while you type:
function greet(user: { name: string }): string {
return "Hello, " + user.name;
}
greet({ name: "Alice" }); // ✓ Works
greet(null); // ✗ Error: Argument of type 'null' is not assignable
greet("Bob"); // ✗ Error: Argument of type 'string' is not assignable
The errors appear instantly in your editor, before you even run the code.
Basic Types
Primitives
let name: string = "Alice";
let age: number = 30;
let isActive: boolean = true;
let nothing: null = null;
let notDefined: undefined = undefined;
Arrays
let numbers: number[] = [1, 2, 3];
let names: string[] = ["Alice", "Bob"];
// Alternative syntax
let numbers: Array = [1, 2, 3];
Objects
let user: { name: string; age: number } = {
name: "Alice",
age: 30
};
Functions
// Parameter and return types
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;
}
Type Inference
TypeScript is smart. You don't need to annotate everything:
// TypeScript infers these types automatically
let name = "Alice"; // string
let age = 30; // number
let items = [1, 2, 3]; // number[]
// You only need annotations when TypeScript can't infer
function double(n: number) {
return n * 2; // Return type is inferred as number
}
Rule of thumb: add types to function parameters. Let TypeScript infer the rest.
Interfaces and Type Aliases
For reusable object shapes:
// Interface (preferred for objects)
interface User {
id: number;
name: string;
email: string;
isAdmin?: boolean; // Optional property
}
// Type alias (flexible, works for anything)
type UserId = number;
type UserList = User[];
type Status = "pending" | "active" | "inactive"; // Union type
// Using them
function getUser(id: UserId): User {
// ...
}
Union Types
When a value can be one of several types:
// String or number
let id: string | number;
id = "abc"; // ✓
id = 123; // ✓
id = true; // ✗ Error
// Literal unions (like enums, but simpler)
type Status = "pending" | "approved" | "rejected";
function setStatus(status: Status) {
// TypeScript knows status can only be these three values
}
Generics
Make reusable components that work with any type:
// Without generics: loses type information
function firstItem(arr: any[]): any {
return arr[0];
}
// With generics: preserves type
function firstItem(arr: T[]): T | undefined {
return arr[0];
}
const num = firstItem([1, 2, 3]); // type: number | undefined
const str = firstItem(["a", "b"]); // type: string | undefined
Getting Started
Option 1: Add to an Existing Project
npm install typescript --save-dev
npx tsc --init
Rename files from .js to .ts and fix errors as they appear.
Option 2: Start Fresh
npx create-react-app my-app --template typescript
or
npx create-next-app my-app --typescript
IDE Setup
VS Code has excellent TypeScript support built-in. You'll get:
- Autocomplete based on types
- Error highlighting as you type
- Hover information showing types
- Go-to-definition across your codebase
Common Questions
"Isn't TypeScript slower to write?"
Initially, yes. But you save that time later:
- Fewer bugs to debug
- Autocomplete speeds up coding
- Refactoring is safer
"Do I need to type everything?"
No. Start with function parameters and let inference handle the rest. Add more types as needed.
"Will it slow down my app?"
TypeScript compiles to plain JavaScript. At runtime, it's identical. Zero performance cost.
"Can I use JavaScript libraries?"
Yes. Most popular libraries have type definitions. Install them:
npm install lodash
npm install @types/lodash --save-dev
A Simple Conversion Example
JavaScript
function processOrder(order) {
const total = order.items.reduce((sum, item) => sum + item.price, 0);
return {
...order,
total,
processedAt: new Date()
};
}
TypeScript
interface OrderItem {
name: string;
price: number;
quantity: number;
}
interface Order {
id: string;
items: OrderItem[];
customer: string;
}
interface ProcessedOrder extends Order {
total: number;
processedAt: Date;
}
function processOrder(order: Order): ProcessedOrder {
const total = order.items.reduce((sum, item) => sum + item.price, 0);
return {
...order,
total,
processedAt: new Date()
};
}
Now if you try to call processOrder with invalid data, you get an error immediately.
Key Takeaway
TypeScript is JavaScript that scales. For small scripts, plain JavaScript is fine. For apps that grow over time and involve multiple developers, TypeScript prevents bugs, improves documentation, and makes refactoring safe.
Start small: add TypeScript to one part of your project, see the benefits, and expand from there.
Further Reading
The official TypeScript Handbook is excellent. For interactive learning, try Total TypeScript tutorials.