← Back to list

solid-principles
by aiskillstore
Security-audited skills for Claude, Codex & Claude Code. One-click install, quality verified.
⭐ 102🍴 3📅 Jan 23, 2026
SKILL.md
name: solid-principles description: SOLID principles adapted for functional and TypeScript-first development.
SOLID Principles for Node.js/TypeScript
Overview
SOLID principles adapted for functional and TypeScript-first development.
S - Single Responsibility Principle
A module/function should have only one reason to change.
Violation
// Bad: Does validation, processing, and notification
const processOrder = async (order: Order) => {
// Validation
if (!order.items.length) throw new Error('Empty order');
if (order.total < 0) throw new Error('Invalid total');
// Processing
const processed = { ...order, status: 'processed' };
await db.orders.save(processed);
// Notification
await emailService.send(order.userId, 'Order confirmed');
return processed;
};
Correct
// Good: Separate responsibilities
const validateOrder = (order: Order): Result<Order, ValidationError> => {
if (!order.items.length) return Result.fail(emptyOrderError());
if (order.total < 0) return Result.fail(invalidTotalError());
return Result.ok(order);
};
const saveOrder = (db: Database) =>
async (order: Order): Promise<Order> => {
const processed = { ...order, status: 'processed' };
await db.orders.save(processed);
return processed;
};
const notifyUser = (notifier: Notifier) =>
async (userId: string, message: string): Promise<void> => {
await notifier.send(userId, message);
};
// Compose in orchestrator
const processOrder = async (order: Order) => {
const validation = validateOrder(order);
if (validation.isFailure) return validation;
const saved = await saveOrder(db)(validation.value);
await notifyUser(emailService)(saved.userId, 'Order confirmed');
return Result.ok(saved);
};
O - Open/Closed Principle
Open for extension, closed for modification.
Violation
// Bad: Must modify function to add new discount types
const calculateDiscount = (type: string, amount: number): number => {
if (type === 'percentage') return amount * 0.1;
if (type === 'fixed') return 10;
if (type === 'loyalty') return amount * 0.15;
return 0;
};
Correct
// Good: Extend via new strategies without modifying existing code
type DiscountStrategy = (amount: number) => number;
const discountStrategies: Record<string, DiscountStrategy> = {
percentage: (amount) => amount * 0.1,
fixed: () => 10,
loyalty: (amount) => amount * 0.15,
};
// Easy to extend
discountStrategies.holiday = (amount) => amount * 0.25;
const calculateDiscount = (type: string, amount: number): number =>
discountStrategies[type]?.(amount) ?? 0;
L - Liskov Substitution Principle
Subtypes must be substitutable for their base types.
Violation
// Bad: Square breaks Rectangle contract
class Rectangle {
constructor(public width: number, public height: number) {}
setWidth(w: number) { this.width = w; }
setHeight(h: number) { this.height = h; }
area() { return this.width * this.height; }
}
class Square extends Rectangle {
setWidth(w: number) {
this.width = w;
this.height = w; // Breaks expectation!
}
}
Correct
// Good: Use composition and explicit types
type Shape = {
area: () => number;
};
const createRectangle = (width: number, height: number): Shape => ({
area: () => width * height,
});
const createSquare = (side: number): Shape => ({
area: () => side * side,
});
I - Interface Segregation Principle
Clients should not depend on interfaces they don't use.
Violation
// Bad: Fat interface
interface DataService {
read(id: string): Promise<Data>;
write(data: Data): Promise<void>;
delete(id: string): Promise<void>;
backup(): Promise<void>;
restore(): Promise<void>;
migrate(): Promise<void>;
}
// Client only needs read
const reportGenerator = (service: DataService) => {
// Only uses service.read(), but depends on entire interface
};
Correct
// Good: Segregated interfaces
type Reader<T> = {
read: (id: string) => Promise<T>;
};
type Writer<T> = {
write: (data: T) => Promise<void>;
};
type Deletable = {
delete: (id: string) => Promise<void>;
};
// Client depends only on what it needs
const reportGenerator = (reader: Reader<ReportData>) => {
// Only depends on read capability
};
// Compose interfaces as needed
type DataService = Reader<Data> & Writer<Data> & Deletable;
D - Dependency Inversion Principle
Depend on abstractions, not concretions.
Violation
// Bad: Direct dependency on implementation
import { PrismaClient } from '@prisma/client';
const createUserService = () => {
const prisma = new PrismaClient(); // Hardcoded!
return {
findUser: (id: string) => prisma.user.findFirst({ where: { id } }),
};
};
Correct
// Good: Depend on abstraction
type UserRepository = {
findById: (id: string) => Promise<User | null>;
save: (user: User) => Promise<User>;
};
const createUserService = (repo: UserRepository) => ({
findUser: (id: string) => repo.findById(id),
createUser: async (data: CreateUserData) => {
const user = { id: generateId(), ...data };
return repo.save(user);
},
});
// Inject implementation
const prismaRepo: UserRepository = {
findById: (id) => prisma.user.findFirst({ where: { id } }),
save: (user) => prisma.user.create({ data: user }),
};
const service = createUserService(prismaRepo);
SOLID in Practice
Factory Function Pattern
// Follows all SOLID principles
type Dependencies = {
userRepo: UserRepository;
orderRepo: OrderRepository;
paymentGateway: PaymentGateway;
logger: Logger;
};
const createOrderProcessor = (deps: Dependencies) => {
const validateOrder = (order: Order): Result<Order, ValidationError> => {
// Single responsibility: validation only
};
const processPayment = async (order: Order): Promise<Result<Payment, PaymentError>> => {
// Single responsibility: payment only
};
return {
process: async (order: Order): Promise<Result<ProcessedOrder, OrderError>> => {
const validation = validateOrder(order);
if (validation.isFailure) return validation;
const payment = await processPayment(validation.value);
if (payment.isFailure) return payment;
// Compose results
return Result.ok({ order: validation.value, payment: payment.value });
},
};
};
Testing SOLID Code
describe('OrderProcessor', () => {
it('should process valid order', async () => {
// Easy to test due to dependency injection
const deps = {
userRepo: createFakeUserRepo(),
orderRepo: createFakeOrderRepo(),
paymentGateway: { charge: jest.fn().mockResolvedValue(Result.ok({})) },
logger: { info: jest.fn() },
};
const processor = createOrderProcessor(deps);
const result = await processor.process(createTestOrder());
expect(result.isSuccess).toBe(true);
});
});
Score
Total Score
60/100
Based on repository quality metrics
✓SKILL.md
SKILL.mdファイルが含まれている
+20
○LICENSE
ライセンスが設定されている
0/10
○説明文
100文字以上の説明がある
0/10
✓人気
GitHub Stars 100以上
+5
✓最近の活動
1ヶ月以内に更新
+10
○フォーク
10回以上フォークされている
0/5
✓Issue管理
オープンIssueが50未満
+5
✓言語
プログラミング言語が設定されている
+5
✓タグ
1つ以上のタグが設定されている
+5
Reviews
💬
Reviews coming soon
