DEV Community

CodeWithDhanian
CodeWithDhanian

Posted on

Developing Linked Lists Using TypeScript: A Programmer’s Handbook

Working with data structures is a fundamental part of software development. Among them, the linked list is one of the most foundational yet powerful structures. While arrays offer indexed access and built-in convenience, linked lists provide a deeper understanding of how memory, references, and dynamic structures work under the hood.

In this guide, we will walk through the creation and manipulation of singly and doubly linked lists using TypeScript. We'll explore their inner workings, offer clean and understandable code, and ensure that developers—whether learning or refining—leave with clarity and confidence.

Table of Contents

  1. What is a Linked List?
  2. Why Use a Linked List?
  3. Creating a Singly Linked List in TypeScript
  4. Implementing Core Operations
  • Insert (Head, Tail, Specific Position)
  • Delete (Head, Tail, Specific Position)
  • Search
  • Traverse
    1. Implementing a Doubly Linked List
    2. Real-World Use Cases
    3. Final Thoughts
    4. TypeScript Ebook for Deeper Learning

1. What is a Linked List?

A linked list is a linear data structure in which elements (called nodes) are connected via pointers. Each node contains two parts:

  • The data it stores.
  • A reference (or pointer) to the next node.

There are two main types:

  • Singly Linked List – Each node points to the next node.
  • Doubly Linked List – Each node points to both the next and previous nodes.

2. Why Use a Linked List?

While arrays provide constant-time access, their size is fixed and insertions/removals are expensive. Linked lists, on the other hand:

  • Allow dynamic memory allocation.
  • Enable efficient insertions and deletions at any position.
  • Are great for applications like memory management, queues, undo/redo features, and more.

3. Creating a Singly Linked List in TypeScript

Let’s start by defining a Node and a LinkedList class.

Node Definition

class ListNode<T> {
  value: T;
  next: ListNode<T> | null;

  constructor(value: T) {
    this.value = value;
    this.next = null;
  }
}
Enter fullscreen mode Exit fullscreen mode

Singly Linked List Class

class SinglyLinkedList<T> {
  private head: ListNode<T> | null = null;

  // Insert at end
  append(value: T): void {
    const newNode = new ListNode(value);

    if (!this.head) {
      this.head = newNode;
      return;
    }

    let current = this.head;
    while (current.next) {
      current = current.next;
    }

    current.next = newNode;
  }

  // Insert at beginning
  prepend(value: T): void {
    const newNode = new ListNode(value);
    newNode.next = this.head;
    this.head = newNode;
  }

  // Traverse and print
  print(): void {
    let current = this.head;
    let output = '';
    while (current) {
      output += `${current.value} -> `;
      current = current.next;
    }
    console.log(output + 'null');
  }
}
Enter fullscreen mode Exit fullscreen mode

4. Implementing Core Operations

Insert at Specific Position

insertAt(value: T, index: number): void {
  if (index < 0) return;

  if (index === 0) {
    this.prepend(value);
    return;
  }

  const newNode = new ListNode(value);
  let current = this.head;
  let previous: ListNode<T> | null = null;
  let count = 0;

  while (current && count < index) {
    previous = current;
    current = current.next;
    count++;
  }

  newNode.next = current;
  if (previous) previous.next = newNode;
}
Enter fullscreen mode Exit fullscreen mode

Delete at Specific Position

deleteAt(index: number): void {
  if (!this.head || index < 0) return;

  if (index === 0) {
    this.head = this.head.next;
    return;
  }

  let current = this.head;
  let previous: ListNode<T> | null = null;
  let count = 0;

  while (current && count < index) {
    previous = current;
    current = current.next;
    count++;
  }

  if (previous && current) {
    previous.next = current.next;
  }
}
Enter fullscreen mode Exit fullscreen mode

Search a Value

find(value: T): boolean {
  let current = this.head;
  while (current) {
    if (current.value === value) return true;
    current = current.next;
  }
  return false;
}
Enter fullscreen mode Exit fullscreen mode

5. Implementing a Doubly Linked List

The main difference is that each node will now store a prev pointer.

Node Definition

class DoublyNode<T> {
  value: T;
  next: DoublyNode<T> | null = null;
  prev: DoublyNode<T> | null = null;

  constructor(value: T) {
    this.value = value;
  }
}
Enter fullscreen mode Exit fullscreen mode

Doubly Linked List Class

class DoublyLinkedList<T> {
  private head: DoublyNode<T> | null = null;
  private tail: DoublyNode<T> | null = null;

  append(value: T): void {
    const newNode = new DoublyNode(value);

    if (!this.head) {
      this.head = this.tail = newNode;
      return;
    }

    if (this.tail) {
      this.tail.next = newNode;
      newNode.prev = this.tail;
      this.tail = newNode;
    }
  }

  printForward(): void {
    let current = this.head;
    let output = '';
    while (current) {
      output += `${current.value} <-> `;
      current = current.next;
    }
    console.log(output + 'null');
  }

  printBackward(): void {
    let current = this.tail;
    let output = '';
    while (current) {
      output += `${current.value} <-> `;
      current = current.prev;
    }
    console.log(output + 'null');
  }
}
Enter fullscreen mode Exit fullscreen mode

6. Real-World Use Cases

  • Undo/Redo stacks in text editors (doubly linked list)
  • Queue management systems (linked list-based queue)
  • Browser history navigation
  • Memory-efficient list handling when insert/delete performance is prioritized

Conclusion

TypeScript, with its static typing, makes implementing data structures like linked lists both safer and more maintainable. Whether you're preparing for coding interviews, building low-level libraries, or deepening your algorithmic thinking, mastering linked lists is a valuable step.

8. Learn More with the TypeScript Ebook

If you're serious about advancing your TypeScript skills, check out the comprehensive TypeScript Handbook for Beginners to Advanced by Dhanian.

What’s Inside:

  • TypeScript fundamentals and configuration
  • Working with types, interfaces, enums, generics, and advanced patterns
  • Building real-world applications using TypeScript
  • DOM manipulation, OOP, modular architecture
  • Exercises and projects to reinforce learning

It’s a complete guide to help you go from beginner to advanced with TypeScript—perfect for developers who want to write clean, type-safe JavaScript at scale.

Top comments (0)