TypeScript Complete Guide: From Beginner to Expert Level
TypeScript Complete Guide: From Beginner to Expert Level
TypeScript has revolutionized JavaScript development by adding static type checking and powerful tooling. Whether you're just starting or looking to master advanced concepts, this guide will take you through everything you need to know.
Table of Contents
1. [Getting Started](#getting-started)
2. [Basic Types](#basic-types)
3. [Functions and Interfaces](#functions-and-interfaces)
4. [Classes and Inheritance](#classes-and-inheritance)
5. [Advanced Types](#advanced-types)
6. [Generics](#generics)
7. [Utility Types](#utility-types)
8. [Decorators](#decorators)
9. [Expert Patterns](#expert-patterns)
10. [Best Practices](#best-practices)
Getting Started
What is TypeScript?
TypeScript is a superset of JavaScript that compiles to plain JavaScript. It adds optional static type checking, which helps catch errors during development rather than at runtime.
Installation
1# Install TypeScript globally2npm install -g typescript3 4# Or install locally in your project5npm install --save-dev typescript6 7# Initialize TypeScript configuration8tsc --initBasic Configuration
Create a tsconfig.json file:
1{2 "compilerOptions": {3 "target": "ES2020",4 "module": "ESNext",5 "lib": ["ES2020", "DOM"],6 "outDir": "./dist",7 "rootDir": "./src",8 "strict": true,9 "esModuleInterop": true,10 "skipLibCheck": true,11 "forceConsistentCasingInFileNames": true,12 "moduleResolution": "node",13 "resolveJsonModule": true,14 "declaration": true,15 "declarationMap": true,Basic Types
Primitive Types
TypeScript provides several primitive types:
1// Boolean2let isActive: boolean = true;3let isComplete: boolean = false;4 5// Numbers6let count: number = 42;7let price: number = 99.99;8let hex: number = 0xf00d;9let binary: number = 0b1010;10 11// Strings12let name: string = "TypeScript";13let message: string = `Hello, ${name}!`;14 15// Null and UndefinedArrays
1// Array of numbers2let numbers: number[] = [1, 2, 3, 4, 5];3 4// Alternative syntax5let items: Array<number> = [1, 2, 3, 4, 5];6 7// Mixed arrays (tuples)8let tuple: [string, number] = ["hello", 42];9let coordinates: [number, number, number] = [10, 20, 30];Enums
1// Numeric enum2enum Status {3 Pending,4 InProgress,5 Completed,6 Cancelled7}8 9let currentStatus: Status = Status.InProgress;10 11// String enum12enum Direction {13 Up = "UP",14 Down = "DOWN",15 Left = "LEFT",Any, Unknown, and Type Assertions
1// Any (avoid when possible)2let dynamicValue: any = "anything";3dynamicValue = 42;4dynamicValue = true;5 6// Unknown (safer than any)7function getUserInput(): unknown {8 return "user input from form";9}10let userInput: unknown = getUserInput();11 12// Type assertion13if (typeof userInput === "string") {14 let strLength: number = userInput.length;15}Functions and Interfaces
Function Types
1// Function declaration2function add(a: number, b: number): number {3 return a + b;4}5 6// Function expression7const multiply = function(x: number, y: number): number {8 return x * y;9};10 11// Arrow function12const divide = (a: number, b: number): number => {13 return a / b;14};15 Interfaces
1// Basic interface2interface User {3 id: number;4 name: string;5 email: string;6 age?: number; // Optional property7 readonly createdAt: Date; // Readonly property8}9 10// Interface with methods11interface Calculator {12 add(a: number, b: number): number;13 subtract(a: number, b: number): number;14 multiply(a: number, b: number): number;15}Type Aliases
1// Type alias2type ID = string | number;3type Status = "active" | "inactive" | "pending";4 5// Complex type alias6type User = {7 id: ID;8 name: string;9 status: Status;10};11 12// Union types13type StringOrNumber = string | number;14type Result<T> = { success: true; data: T } | { success: false; error: string };15 Classes and Inheritance
Basic Classes
1class Animal {2 // Public properties (default)3 public name: string;4 5 // Private properties6 private age: number;7 8 // Protected properties (accessible in subclasses)9 protected species: string;10 11 // Readonly properties12 readonly id: string;13 14 // Constructor15 constructor(name: string, age: number, species: string) {Abstract Classes
1abstract class Shape {2 abstract calculateArea(): number;3 abstract calculatePerimeter(): number;4 5 displayInfo(): void {6 console.log(`Area: ${this.calculateArea()}, Perimeter: ${this.calculatePerimeter()}`);7 }8}9 10class Circle extends Shape {11 constructor(private radius: number) {12 super();13 }14 15 calculateArea(): number {Getters and Setters
1class Temperature {2 private _celsius: number = 0;3 4 get celsius(): number {5 return this._celsius;6 }7 8 set celsius(value: number) {9 if (value < -273.15) {10 throw new Error("Temperature cannot be below absolute zero");11 }12 this._celsius = value;13 }14 15 get fahrenheit(): number {Advanced Types
Union and Intersection Types
1// Union types2type StringOrNumber = string | number;3 4function formatValue(value: StringOrNumber): string {5 if (typeof value === "string") {6 return value.toUpperCase();7 }8 return value.toString();9}10 11// Intersection types12type Person = {13 name: string;14 age: number;15};Type Guards
1// Type guard functions2function isString(value: unknown): value is string {3 return typeof value === "string";4}5 6function isNumber(value: unknown): value is number {7 return typeof value === "number";8}9 10// Custom type guard11interface Bird {12 fly(): void;13 layEggs(): void;14}15 Discriminated Unions
1type Success = {2 type: "success";3 data: any;4};5 6type Error = {7 type: "error";8 message: string;9};10 11type Result = Success | Error;12 13function handleResult(result: Result) {14 switch (result.type) {15 case "success":Mapped Types
1// Make all properties optional2type Partial<T> = {3 [P in keyof T]?: T[P];4};5 6// Make all properties required7type Required<T> = {8 [P in keyof T]-?: T[P];9};10 11// Make all properties readonly12type Readonly<T> = {13 readonly [P in keyof T]: T[P];14};15 Conditional Types
1// Basic conditional type2type IsArray<T> = T extends Array<any> ? true : false;3 4type Test1 = IsArray<string[]>; // true5type Test2 = IsArray<string>; // false6 7// Extract array element type8type ArrayElement<T> = T extends Array<infer U> ? U : never;9 10type Element = ArrayElement<string[]>; // string11 12// Non-nullable type13type NonNullable<T> = T extends null | undefined ? never : T;14 15// Function return type extractorGenerics
Basic Generics
1// Generic function2function identity<T>(arg: T): T {3 return arg;4}5 6let output1 = identity<string>("hello");7let output2 = identity<number>(42);8let output3 = identity("hello"); // Type inference9 10// Generic interface11interface Container<T> {12 value: T;13 getValue(): T;14 setValue(value: T): void;15}Generic Constraints
1// Constraint with interface2interface Lengthwise {3 length: number;4}5 6function logLength<T extends Lengthwise>(arg: T): T {7 console.log(arg.length);8 return arg;9}10 11// Using keyof12function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {13 return obj[key];14}15 Generic Classes
1class Repository<T> {2 private items: T[] = [];3 4 add(item: T): void {5 this.items.push(item);6 }7 8 findById(id: number): T | undefined {9 return this.items.find((item: any) => item.id === id);10 }11 12 findAll(): T[] {13 return [...this.items];14 }15 Utility Types
TypeScript provides several built-in utility types:
1interface User {2 id: number;3 name: string;4 email: string;5 age: number;6 active: boolean;7}8 9// Partial - makes all properties optional10type PartialUser = Partial<User>;11 12// Required - makes all properties required13type RequiredUser = Required<PartialUser>;14 15// Readonly - makes all properties readonlyDecorators
Class Decorators
1// Enable decorators in tsconfig.json2// "experimentalDecorators": true3 4function sealed(constructor: Function) {5 Object.seal(constructor);6 Object.seal(constructor.prototype);7}8 9@sealed10class Greeter {11 greeting: string;12 constructor(message: string) {13 this.greeting = message;14 }15 greet() {Method Decorators
1function enumerable(value: boolean) {2 return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {3 descriptor.enumerable = value;4 };5}6 7class Greeter {8 greeting: string;9 constructor(message: string) {10 this.greeting = message;11 }12 13 @enumerable(false)14 greet() {15 return "Hello, " + this.greeting;Property Decorators
1function format(target: any, propertyKey: string) {2 let value = target[propertyKey];3 4 const getter = function () {5 return value;6 };7 8 const setter = function (newVal: string) {9 value = newVal.toUpperCase();10 };11 12 Object.defineProperty(target, propertyKey, {13 get: getter,14 set: setter,15 enumerable: true,Expert Patterns
Builder Pattern
1class QueryBuilder {2 private selectFields: string[] = [];3 private fromTable: string = "";4 private whereConditions: string[] = [];5 private orderByField: string = "";6 7 select(fields: string[]): this {8 this.selectFields = fields;9 return this;10 }11 12 from(table: string): this {13 this.fromTable = table;14 return this;15 }Factory Pattern
1interface Product {2 name: string;3 price: number;4 getDescription(): string;5}6 7class Book implements Product {8 constructor(public name: string, public price: number) {}9 10 getDescription(): string {11 return `Book: ${this.name} - $${this.price}`;12 }13}14 15class Electronics implements Product {Singleton Pattern
1class DatabaseConnection {2 private static instance: DatabaseConnection;3 private connectionString: string;4 5 private constructor(connectionString: string) {6 this.connectionString = connectionString;7 }8 9 public static getInstance(connectionString?: string): DatabaseConnection {10 if (!DatabaseConnection.instance) {11 if (!connectionString) {12 throw new Error("Connection string required for first initialization");13 }14 DatabaseConnection.instance = new DatabaseConnection(connectionString);15 }Observer Pattern
1interface Observer<T> {2 update(data: T): void;3}4 5class Subject<T> {6 private observers: Observer<T>[] = [];7 8 attach(observer: Observer<T>): void {9 this.observers.push(observer);10 }11 12 detach(observer: Observer<T>): void {13 const index = this.observers.indexOf(observer);14 if (index > -1) {15 this.observers.splice(index, 1);Dependency Injection
1interface ILogger {2 log(message: string): void;3}4 5class ConsoleLogger implements ILogger {6 log(message: string): void {7 console.log(`[LOG] ${message}`);8 }9}10 11class FileLogger implements ILogger {12 log(message: string): void {13 // File logging implementation14 console.log(`[FILE] ${message}`);15 }Best Practices
1. Use Strict Mode
Always enable strict mode in tsconfig.json:
1{2 "compilerOptions": {3 "strict": true4 }5}2. Prefer Interfaces for Object Shapes
1// Good2interface User {3 name: string;4 age: number;5}6 7// Use type aliases for unions, intersections, and complex types8type Status = "active" | "inactive";9type UserWithStatus = User & { status: Status };3. Avoid Using `any`
1// Bad2function processData(data: any) {3 return data.value;4}5 6// Good7function processData<T extends { value: unknown }>(data: T): T["value"] {8 return data.value;9}4. Use Type Guards
1// Good2function isString(value: unknown): value is string {3 return typeof value === "string";4}5 6if (isString(value)) {7 // TypeScript knows value is string here8 console.log(value.toUpperCase());9}5. Leverage Utility Types
1// Instead of manually creating partial types2type PartialUser = {3 name?: string;4 age?: number;5 email?: string;6};7 8// Use built-in utility9type PartialUser = Partial<User>;6. Use Enums for Constants
1// Good2enum HttpStatus {3 OK = 200,4 NotFound = 404,5 ServerError = 5006}7 8// Or const assertions for simple cases9const Status = {10 Active: "active",11 Inactive: "inactive"12} as const;7. Document Complex Types
1/**2 * Represents a user in the system3 * @property id - Unique identifier4 * @property name - User's full name5 * @property email - Valid email address6 */7interface User {8 id: number;9 name: string;10 email: string;11}8. Use Readonly for Immutability
1interface Config {2 readonly apiUrl: string;3 readonly timeout: number;4}5 6const config: Config = {7 apiUrl: "https://api.example.com",8 timeout: 50009};10 11// config.apiUrl = "new url"; // Error!Conclusion
TypeScript is a powerful tool that enhances JavaScript development with type safety, better tooling, and improved code maintainability. This guide covered everything from basic types to advanced patterns.
Key takeaways:
Continue practicing and building projects to solidify your TypeScript skills. The type system becomes more powerful as you learn to leverage its advanced features.
Happy coding with TypeScript!
Enjoyed this article?
Support our work and help us create more free content for developers.
Stay Updated
Get the latest articles and updates delivered to your inbox.