Featured

TypeScript Complete Guide: From Beginner to Expert Level

T
Team
·25 min read
#typescript#programming#web development#javascript#types#generics

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


bash
1# Install TypeScript globally
2npm install -g typescript
3 
4# Or install locally in your project
5npm install --save-dev typescript
6 
7# Initialize TypeScript configuration
8tsc --init

Basic Configuration


Create a tsconfig.json file:


json(20 lines, showing 15)
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:


typescript(27 lines, showing 15)
1// Boolean
2let isActive: boolean = true;
3let isComplete: boolean = false;
4 
5// Numbers
6let count: number = 42;
7let price: number = 99.99;
8let hex: number = 0xf00d;
9let binary: number = 0b1010;
10 
11// Strings
12let name: string = "TypeScript";
13let message: string = `Hello, ${name}!`;
14 
15// Null and Undefined

Arrays


typescript
1// Array of numbers
2let numbers: number[] = [1, 2, 3, 4, 5];
3 
4// Alternative syntax
5let 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


typescript(25 lines, showing 15)
1// Numeric enum
2enum Status {
3 Pending,
4 InProgress,
5 Completed,
6 Cancelled
7}
8 
9let currentStatus: Status = Status.InProgress;
10 
11// String enum
12enum Direction {
13 Up = "UP",
14 Down = "DOWN",
15 Left = "LEFT",

Any, Unknown, and Type Assertions


typescript(19 lines, showing 15)
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 assertion
13if (typeof userInput === "string") {
14 let strLength: number = userInput.length;
15}

Functions and Interfaces


Function Types


typescript(29 lines, showing 15)
1// Function declaration
2function add(a: number, b: number): number {
3 return a + b;
4}
5 
6// Function expression
7const multiply = function(x: number, y: number): number {
8 return x * y;
9};
10 
11// Arrow function
12const divide = (a: number, b: number): number => {
13 return a / b;
14};
15 

Interfaces


typescript(30 lines, showing 15)
1// Basic interface
2interface User {
3 id: number;
4 name: string;
5 email: string;
6 age?: number; // Optional property
7 readonly createdAt: Date; // Readonly property
8}
9 
10// Interface with methods
11interface 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


typescript(25 lines, showing 15)
1// Type alias
2type ID = string | number;
3type Status = "active" | "inactive" | "pending";
4 
5// Complex type alias
6type User = {
7 id: ID;
8 name: string;
9 status: Status;
10};
11 
12// Union types
13type StringOrNumber = string | number;
14type Result<T> = { success: true; data: T } | { success: false; error: string };
15 

Classes and Inheritance


Basic Classes


typescript(56 lines, showing 15)
1class Animal {
2 // Public properties (default)
3 public name: string;
4
5 // Private properties
6 private age: number;
7
8 // Protected properties (accessible in subclasses)
9 protected species: string;
10
11 // Readonly properties
12 readonly id: string;
13
14 // Constructor
15 constructor(name: string, age: number, species: string) {

Abstract Classes


typescript(36 lines, showing 15)
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


typescript(22 lines, showing 15)
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


typescript(29 lines, showing 15)
1// Union types
2type 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 types
12type Person = {
13 name: string;
14 age: number;
15};

Type Guards


typescript(31 lines, showing 15)
1// Type guard functions
2function 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 guard
11interface Bird {
12 fly(): void;
13 layEggs(): void;
14}
15 

Discriminated Unions


typescript(22 lines, showing 15)
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


typescript(27 lines, showing 15)
1// Make all properties optional
2type Partial<T> = {
3 [P in keyof T]?: T[P];
4};
5 
6// Make all properties required
7type Required<T> = {
8 [P in keyof T]-?: T[P];
9};
10 
11// Make all properties readonly
12type Readonly<T> = {
13 readonly [P in keyof T]: T[P];
14};
15 

Conditional Types


typescript(16 lines, showing 15)
1// Basic conditional type
2type IsArray<T> = T extends Array<any> ? true : false;
3 
4type Test1 = IsArray<string[]>; // true
5type Test2 = IsArray<string>; // false
6 
7// Extract array element type
8type ArrayElement<T> = T extends Array<infer U> ? U : never;
9 
10type Element = ArrayElement<string[]>; // string
11 
12// Non-nullable type
13type NonNullable<T> = T extends null | undefined ? never : T;
14 
15// Function return type extractor

Generics


Basic Generics


typescript(30 lines, showing 15)
1// Generic function
2function 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 inference
9 
10// Generic interface
11interface Container<T> {
12 value: T;
13 getValue(): T;
14 setValue(value: T): void;
15}

Generic Constraints


typescript(18 lines, showing 15)
1// Constraint with interface
2interface 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 keyof
12function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
13 return obj[key];
14}
15 

Generic Classes


typescript(32 lines, showing 15)
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:


typescript(44 lines, showing 15)
1interface User {
2 id: number;
3 name: string;
4 email: string;
5 age: number;
6 active: boolean;
7}
8 
9// Partial - makes all properties optional
10type PartialUser = Partial<User>;
11 
12// Required - makes all properties required
13type RequiredUser = Required<PartialUser>;
14 
15// Readonly - makes all properties readonly

Decorators


Class Decorators


typescript(30 lines, showing 15)
1// Enable decorators in tsconfig.json
2// "experimentalDecorators": true
3 
4function sealed(constructor: Function) {
5 Object.seal(constructor);
6 Object.seal(constructor.prototype);
7}
8 
9@sealed
10class Greeter {
11 greeting: string;
12 constructor(message: string) {
13 this.greeting = message;
14 }
15 greet() {

Method Decorators


typescript(36 lines, showing 15)
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


typescript(27 lines, showing 15)
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


typescript(48 lines, showing 15)
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


typescript(36 lines, showing 15)
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


typescript(25 lines, showing 15)
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


typescript(39 lines, showing 15)
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


typescript(30 lines, showing 15)
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 implementation
14 console.log(`[FILE] ${message}`);
15 }

Best Practices


1. Use Strict Mode


Always enable strict mode in tsconfig.json:


json
1{
2 "compilerOptions": {
3 "strict": true
4 }
5}

2. Prefer Interfaces for Object Shapes


typescript
1// Good
2interface User {
3 name: string;
4 age: number;
5}
6 
7// Use type aliases for unions, intersections, and complex types
8type Status = "active" | "inactive";
9type UserWithStatus = User & { status: Status };

3. Avoid Using `any`


typescript
1// Bad
2function processData(data: any) {
3 return data.value;
4}
5 
6// Good
7function processData<T extends { value: unknown }>(data: T): T["value"] {
8 return data.value;
9}

4. Use Type Guards


typescript
1// Good
2function isString(value: unknown): value is string {
3 return typeof value === "string";
4}
5 
6if (isString(value)) {
7 // TypeScript knows value is string here
8 console.log(value.toUpperCase());
9}

5. Leverage Utility Types


typescript
1// Instead of manually creating partial types
2type PartialUser = {
3 name?: string;
4 age?: number;
5 email?: string;
6};
7 
8// Use built-in utility
9type PartialUser = Partial<User>;

6. Use Enums for Constants


typescript
1// Good
2enum HttpStatus {
3 OK = 200,
4 NotFound = 404,
5 ServerError = 500
6}
7 
8// Or const assertions for simple cases
9const Status = {
10 Active: "active",
11 Inactive: "inactive"
12} as const;

7. Document Complex Types


typescript
1/**
2 * Represents a user in the system
3 * @property id - Unique identifier
4 * @property name - User's full name
5 * @property email - Valid email address
6 */
7interface User {
8 id: number;
9 name: string;
10 email: string;
11}

8. Use Readonly for Immutability


typescript
1interface Config {
2 readonly apiUrl: string;
3 readonly timeout: number;
4}
5 
6const config: Config = {
7 apiUrl: "https://api.example.com",
8 timeout: 5000
9};
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:


  • Start with basics: Master primitive types, interfaces, and classes
  • Progress to advanced: Learn generics, utility types, and conditional types
  • Apply patterns: Use design patterns to solve common problems
  • Follow best practices: Enable strict mode, avoid `any`, use type guards

  • 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.