examples/typescript-circular-dependency/SKILL.md
Detect and resolve TypeScript/JavaScript circular import dependencies. Use when: (1) Cannot access X before initialization at runtime, (2) Import returns undefined unexpectedly, (3) ReferenceError Cannot access X before initialization, (4) Type errors that disappear when you change import order, (5) Jest/Vitest tests fail with undefined imports that work in browser.
npx skillsauth add abhattacherjee/claudeception typescript-circular-dependencyInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Circular dependencies occur when module A imports from module B, which imports
(directly or indirectly) from module A. TypeScript compiles successfully, but at
runtime, one of the imports evaluates to undefined because the module hasn't
finished initializing yet.
Common error messages:
ReferenceError: Cannot access 'UserService' before initialization
TypeError: Cannot read properties of undefined (reading 'create')
TypeError: (0 , _service.doSomething) is not a function
Symptoms that suggest circular imports:
undefined even though the export existsconsole.log at the top of a file changes behaviorUse a tool to visualize dependencies:
# Install madge
npm install -g madge
# Find circular dependencies
madge --circular --extensions ts,tsx src/
# Generate visual graph
madge --circular --image graph.svg src/
Or use the TypeScript compiler:
# Check for cycles (requires tsconfig setting)
npx tsc --listFiles | head -50
Common circular dependency patterns:
Pattern A: Service-to-Service
services/userService.ts → services/orderService.ts → services/userService.ts
Pattern B: Type imports
types/user.ts → types/order.ts → types/user.ts
Pattern C: Index barrel files
components/index.ts → components/Button.tsx → components/index.ts
Strategy 1: Extract Shared Dependencies
Before:
// userService.ts
import { OrderService } from './orderService';
export class UserService { ... }
// orderService.ts
import { UserService } from './userService';
export class OrderService { ... }
After:
// types/interfaces.ts (new file - no imports from services)
export interface IUserService { ... }
export interface IOrderService { ... }
// userService.ts
import { IOrderService } from '../types/interfaces';
export class UserService implements IUserService { ... }
Strategy 2: Dependency Injection
// orderService.ts
export class OrderService {
constructor(private userService: IUserService) {}
// Instead of importing UserService directly
}
// main.ts
const userService = new UserService();
const orderService = new OrderService(userService);
Strategy 3: Dynamic Imports
// Only import when needed, not at module level
async function processOrder() {
const { UserService } = await import('./userService');
// ...
}
Strategy 4: Use Type-Only Imports
If you only need types (not values), use type-only imports:
// This doesn't create a runtime dependency
import type { User } from './userService';
Strategy 5: Restructure Barrel Files
Before (problematic):
// components/index.ts
export * from './Button';
export * from './Modal'; // Modal imports Button from './index'
After:
// components/Modal.tsx
import { Button } from './Button'; // Direct import, not from index
Add to your CI/build process:
// package.json
{
"scripts": {
"check:circular": "madge --circular --extensions ts,tsx src/"
}
}
Or configure ESLint:
// .eslintrc.js
module.exports = {
plugins: ['import'],
rules: {
'import/no-cycle': ['error', { maxDepth: 10 }]
}
}
madge --circular src/ - should report no cyclesnode_modules and reinstall - app should still workProblem: OrderService is undefined when imported in UserService
Detection:
$ madge --circular src/
Circular dependencies found!
src/services/userService.ts → src/services/orderService.ts → src/services/userService.ts
Fix: Extract shared interface
// NEW: src/types/services.ts
export interface IOrderService {
createOrder(userId: string): Promise<Order>;
}
// MODIFIED: src/services/userService.ts
import type { IOrderService } from '../types/services';
export class UserService {
constructor(private orderService: IOrderService) {}
}
// MODIFIED: src/services/orderService.ts
// No longer imports UserService
export class OrderService implements IOrderService {
async createOrder(userId: string): Promise<Order> { ... }
}
import type is your friend—it's erased at runtime and can't cause cyclesindex.ts) are a common source of accidental cyclesrequire() can sometimes mask circular dependency issues that import exposesdevops
Fix Prisma Too many connections and connection pool exhaustion errors in serverless environments (Vercel, AWS Lambda, Netlify). Use when: (1) Error P2024 Timed out fetching a new connection from the pool, (2) PostgreSQL too many connections for role, (3) Database works locally but fails in production serverless, (4) Intermittent database timeouts under load.
tools
Debug getServerSideProps and getStaticProps errors in Next.js. Use when: (1) Page shows generic error but browser console is empty, (2) API routes return 500 with no details, (3) Server-side code fails silently, (4) Error only occurs on refresh not client navigation. Check terminal/server logs instead of browser for actual error messages.
development
Extracts reusable knowledge from work sessions and codifies it into Claude Code skills. Use when: (1) /claudeception command to review session learnings, (2) save this as a skill or extract a skill from this, (3) what did we learn?, (4) after non-obvious debugging, workarounds, or trial-and-error discovery. Evaluates whether current work contains extractable knowledge, checks for existing skills, and creates or updates skills following the skill-authoring best practices.
development
Maintainer-only workflow for handling GitHub Secret Scanning alerts on OpenClaw. Use when Codex needs to triage, redact, clean up, and resolve secret leakage found in issue comments, issue bodies, PR comments, or other GitHub content.