
TypeScript for Frontend Development: A Beginner's Guide
A guide to TypeScript for frontend development for beginners part 1
TypeScript for Frontend Development: A Beginner's Guide
Hello there! Let's start with basic to advanced TypeScript concepts. This is just a guide not a tutorial to learn TypeScript. You can use this as a reference to learn TypeScript. This is the first part of the series.
TypeScript is JavaScript with type safety! It helps catch errors before runtime and makes your code more maintainable.
Table of Contents
- Why TypeScript?
- Basic Types
- Interfaces and Types
- Functions
- Arrays and Tuples
- Union and Intersection
- Generics
- Utility Types
- TypeScript with React
Why TypeScript?
Catch errors before runtime:
// JavaScript - Runtime error
function greet(name) {
return name.toUpperCase();
}
greet(123); // Error at runtime
// TypeScript - Compile error
function greet(name: string) {
return name.toUpperCase();
}
greet(123); // ❌ Error: number not assignable to stringBasic Types
// Primitives
const name: string = 'Alex';
const age: number = 25;
const isActive: boolean = true;
// Arrays
const numbers: number[] = [1, 2, 3];
const names: Array<string> = ['Alice', 'Bob'];
// Type inference (TypeScript figures it out)
const city = 'Tokyo'; // TypeScript knows this is a string
// Any - avoid when possible
let anything: any = 'hello';
anything = 123; // Valid but not recommended
// Unknown - safer alternative
let value: unknown = 'hello';
if (typeof value === 'string') {
console.log(value.toUpperCase()); // Safe after check
}
// Void and Never
function log(msg: string): void {
console.log(msg);
}
function throwError(msg: string): never {
throw new Error(msg);
}Interfaces and Types
Define custom object shapes:
// Interface
interface User {
name: string;
age: number;
email: string;
}
const user: User = {
name: 'Sarah',
age: 28,
email: 'sarah@example.com',
};
// Optional properties
interface Product {
id: string;
name: string;
price: number;
description?: string; // Optional
}
// Readonly
interface Config {
readonly apiKey: string;
timeout: number;
}
// Extending interfaces
interface Employee extends User {
employeeId: string;
department: string;
}
// Type alias
type ID = string | number;
type Status = 'pending' | 'approved' | 'rejected';
type Point = {
x: number;
y: number;
};
// Complex type
type ApiResponse<T> = {
data: T;
status: number;
message: string;
};Functions
Type function parameters and return values:
// Basic function
function add(a: number, b: number): number {
return a + b;
}
// Arrow function
const multiply = (a: number, b: number): number => a * b;
// Optional and default parameters
function greet(name: string, greeting: string = 'Hello'): string {
return `${greeting}, ${name}!`;
}
// Rest parameters
function sum(...numbers: number[]): number {
return numbers.reduce((total, num) => total + num, 0);
}
// Function type
type MathOp = (a: number, b: number) => number;
const divide: MathOp = (a, b) => a / b;Arrays and Tuples
// Typed arrays
const numbers: number[] = [1, 2, 3];
const tasks: Task[] = [
{ id: 1, title: 'Learn TypeScript', done: true },
{ id: 2, title: 'Build project', done: false },
];
// Tuples - fixed length with specific types
type Coordinate = [number, number];
const point: Coordinate = [10, 20];
// Named tuples
type RGB = [red: number, green: number, blue: number];
const color: RGB = [255, 100, 50];
// Optional in tuples
type Response = [status: number, message: string, data?: any];
const success: Response = [200, 'OK', { user: 'Alice' }];Union and Intersection
Union Types
A value can be one of several types:
type ID = string | number;
let userId: ID = 123;
userId = 'abc-123'; // Both valid
type Status = 'loading' | 'success' | 'error';
function printId(id: string | number): void {
if (typeof id === 'string') {
console.log(id.toUpperCase());
} else {
console.log(id);
}
}Intersection Types
Combine multiple types:
type Person = {
name: string;
age: number;
};
type Employee = {
employeeId: string;
department: string;
};
type Staff = Person & Employee;
const staff: Staff = {
name: 'John',
age: 30,
employeeId: 'E123',
department: 'IT',
};Generics
Create reusable, type-safe code:
// Generic function
function identity<T>(value: T): T {
return value;
}
const num = identity(42); // number
const str = identity('hello'); // string
// Generic with constraints
interface HasLength {
length: number;
}
function logLength<T extends HasLength>(item: T): void {
console.log(item.length);
}
logLength('hello'); // 5
logLength([1, 2, 3]); // 3
// Generic interface
interface Box<T> {
value: T;
}
const numberBox: Box<number> = { value: 42 };
// Generic class
class DataStorage<T> {
private data: T[] = [];
add(item: T): void {
this.data.push(item);
}
getAll(): T[] {
return [...this.data];
}
}
const textStorage = new DataStorage<string>();
textStorage.add('Hello');Utility Types
Built-in type helpers:
interface User {
id: string;
name: string;
email: string;
age: number;
}
// Partial - all properties optional
type PartialUser = Partial<User>;
const update: PartialUser = { name: 'Alice' };
// Required - all properties required
type RequiredUser = Required<User>;
// Readonly - all properties readonly
type ReadonlyUser = Readonly<User>;
// Pick - select specific properties
type UserPreview = Pick<User, 'id' | 'name'>;
// Omit - remove specific properties
type UserWithoutEmail = Omit<User, 'email'>;
// Record - create object type
type UserRoles = Record<string, User>;
// ReturnType - get function return type
function getUser() {
return { id: '1', name: 'Alice' };
}
type UserType = ReturnType<typeof getUser>;TypeScript with React
Function Components
interface ButtonProps {
label: string;
onClick: () => void;
disabled?: boolean;
variant?: 'primary' | 'secondary';
}
function Button({ label, onClick, disabled, variant = 'primary' }: ButtonProps) {
return (
<button onClick={onClick} disabled={disabled} className={variant}>
{label}
</button>
);
}Hooks
import { useState, useEffect, useRef } from 'react';
// useState with type inference
const [count, setCount] = useState(0); // number
// useState with explicit type
const [user, setUser] = useState<User | null>(null);
// useState with array
const [items, setItems] = useState<string[]>([]);
// useRef
const inputRef = useRef<HTMLInputElement>(null);
// useEffect
useEffect(() => {
// Effect logic
return () => {
// Cleanup
};
}, [dependency]);Event Handlers
// Click event
const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
console.log('Clicked');
};
// Change event
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
console.log(event.target.value);
};
// Form submit
const handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault();
};Children Props
interface ContainerProps {
children: React.ReactNode;
}
function Container({ children }: ContainerProps) {
return <div>{children}</div>;
}Best Practices
- Enable strict mode in
tsconfig.json - Avoid
any- useunknownwhen necessary - Use type inference when possible
- Prefer interfaces for object shapes
- Use const assertions for immutable data
// ✅ Good
const routes = {
home: '/',
about: '/about',
} as const;
// ❌ Avoid
function processData(data: any) {}
// ✅ Better
function processData(data: unknown) {
if (typeof data === 'string') {
// Safe to use
}
}That's it for this first part of our TypeScript journey! We've covered the essential foundations you need to know before diving deeper into TypeScript with React and other frameworks. In the next part, we'll explore more advanced patterns and build real-world applications.
Remember, the best way to learn is by practicing. Try to experiment with these concepts in your projects. Happy coding! 🚀


