Strategy Pattern
The strategy pattern defines a family of algorithms, puts each in a separate function/class, and makes them interchangeable. The context uses one strategy at a time without knowing the details.
Classic example - sorting
ts
type SortStrategy<T> = (items: T[]) => T[];
const byName: SortStrategy<User> = (users) =>
[...users].sort((a, b) => a.name.localeCompare(b.name));
const byAge: SortStrategy<User> = (users) =>
[...users].sort((a, b) => a.age - b.age);
const byCreatedAt: SortStrategy<User> = (users) =>
[...users].sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime());
// context - doesn't know which strategy is used
function UserList({ users, sortBy }: { users: User[]; sortBy: SortStrategy<User> }) {
const sorted = sortBy(users);
return sorted.map(u => <UserRow key={u.id} user={u} />);
}
<UserList users={users} sortBy={byName} />
<UserList users={users} sortBy={byAge} />Validation strategies
ts
type Validator = (value: string) => string | null; // null = valid
const required: Validator = (v) => v.trim() ? null : 'Required';
const email: Validator = (v) => /^[^@]+@[^@]+$/.test(v) ? null : 'Invalid email';
const minLength = (n: number): Validator =>
(v) => v.length >= n ? null : `Min ${n} characters`;
function validate(value: string, validators: Validator[]): string[] {
return validators.map(v => v(value)).filter(Boolean) as string[];
}
validate(input, [required, email, minLength(5)]);Payment strategies
ts
interface PaymentStrategy {
pay(amount: number): Promise<{ success: boolean; transactionId: string }>;
}
class StripeStrategy implements PaymentStrategy {
async pay(amount: number) { return stripe.charge(amount); }
}
class PayPalStrategy implements PaymentStrategy {
async pay(amount: number) { return paypal.transfer(amount); }
}
class Checkout {
constructor(private strategy: PaymentStrategy) {}
async process(amount: number) { return this.strategy.pay(amount); }
}
const checkout = new Checkout(new StripeStrategy());Strategy is one of the most useful patterns in everyday frontend code. Any time you have
if (type === 'x') ... else if (type === 'y') ...for behavior selection, you likely want a strategy map instead.
updated
did you know it?