← Back to TypeScript Course | Chapter 16: Advanced Patterns | Lesson 5 of 7

Strategy Pattern

The Strategy Pattern places interchangeable algorithms behind a common interface. A context can switch strategies without changing its core logic.
Syntax
typescript
interface Strategy {
  execute(data: type): returnType;
}
class Context {
  constructor(private strategy: Strategy) {}
  run(data: type) { return this.strategy.execute(data); }
}

Basic Strategy

A strategy represents one algorithm behind a common interface, while a context object holds a reference to whichever strategy it was given and delegates the actual work to it.

This means the context never needs an if/else chain to pick behavior — it just calls the strategy it was handed.

Example: Basic Strategy

typescript
interface PaymentStrategy {
  pay(amount: number): string;
}
class CreditCard implements PaymentStrategy {
  pay(amount: number) { return `Paid ${amount} by credit card`; }
}
class Context {
  constructor(private strategy: PaymentStrategy) {}
  checkout(amount: number) { return this.strategy.pay(amount); }
}
console.log(new Context(new CreditCard()).checkout(100));

Switching Strategies

A context can expose a setter so its strategy can be swapped while the program is running, letting the same object change behavior in response to user input, configuration, or runtime conditions without being recreated.

Example: Switching Strategies

typescript
interface PaymentStrategy {
  pay(amount: number): string;
}
class PayPal implements PaymentStrategy {
  pay(amount: number) { return `Paid ${amount} via PayPal`; }
}
class Context {
  private strategy: PaymentStrategy;
  constructor(strategy: PaymentStrategy) { this.strategy = strategy; }
  setStrategy(strategy: PaymentStrategy) { this.strategy = strategy; }
  checkout(amount: number) { return this.strategy.pay(amount); }
}
const ctx = new Context(new PayPal());
console.log(ctx.checkout(50));

Function Strategies

For simple algorithms, a typed function can serve as a strategy without creating a separate class for it — TypeScript's structural typing means any function matching the expected signature is automatically compatible.

Example: Function Strategies

typescript
type SortStrategy = (a: number, b: number) => number;
const ascending: SortStrategy = (a, b) => a - b;
const descending: SortStrategy = (a, b) => b - a;
function sortWith(nums: number[], strategy: SortStrategy) {
  return [...nums].sort(strategy);
}
console.log(sortWith([3, 1, 2], ascending));

Benefits of Strategy

Strategy reduces large conditional blocks and isolates each algorithm so it can be tested, replaced, or extended independently, which matters most once a codebase has several interchangeable variants of the same operation.

Example: Benefits of Strategy

typescript
interface Discount {
  apply(price: number): number;
}
class NoDiscount implements Discount {
  apply(price: number) { return price; }
}
class TenPercentOff implements Discount {
  apply(price: number) { return price * 0.9; }
}
function checkout(price: number, discount: Discount) {
  return discount.apply(price);
}
console.log(checkout(100, new TenPercentOff()));

When to Use Strategy

Use Strategy when an operation genuinely has multiple interchangeable approaches that might change at runtime or grow over time. Avoid it when one simple algorithm is sufficient — the extra interface adds indirection you don't need yet.

Example: When to Use Strategy

typescript
interface Formatter {
  format(value: number): string;
}
class PlainFormatter implements Formatter {
  format(value: number) { return String(value); }
}
function display(value: number, formatter: Formatter) {
  return formatter.format(value);
}
console.log(display(42, new PlainFormatter()));
Related Topics
{# common_mistakes/chapter_summary/browser_support: on Hindi pages the view already swaps in the hi_ translation fields (or blanks these out if untranslated), so this renders correctly for both languages without a lang_code check here. #}
Common Mistakes
  1. Putting if/else on a type string inside the context, which defeats the purpose of separate strategies.
  2. Passing a strategy object that lacks the required method, like pay.
  3. Forgetting to call the strategy method (this.strategy.pay(amount)), and just returning the strategy.
🔒

Chapter Quiz — Complete all 7 topics to unlock

0/7 topics done

Complete these topics first:

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.