Type Reuse Guide

Documentation for Developers

📋 Type Reuse Guide: No Local Types Policy

🚨 CRITICAL RULE: Never Define Local Types

In our NX monorepo, NEVER define types/interfaces locally in service or component files!

This policy prevents build issues, promotes code reuse, and maintains consistency across the monorepo.

✅ Correct Pattern: Models Directory

Required Structure

Every NX library MUST follow this structure:

libs/my-library/
├── src/
│   ├── lib/
│   │   ├── models/              # ← REQUIRED: All types go here
│   │   │   ├── index.ts         # ← Export all models
│   │   │   ├── my-types.ts      # ← Type definitions
│   │   │   └── interfaces.ts    # ← More type definitions  
│   │   ├── services/
│   │   ├── components/
│   │   └── index.ts
│   └── index.ts            # ← Must export models

Step 1: Define Types in Models Directory

// libs/my-library/src/lib/models/my-service.types.ts
import type { SafeAny } from '@libs-foundational/core-models'; 

export interface MyServiceConfig {
  apiUrl: string;
  timeout?: number;
  retries?: number;
}

export interface MyServiceState {
  loading: boolean;
  error: Error | null;
  data: SafeAny[];
}

Step 2: Export from Models Index

// libs/my-library/src/lib/models/index.ts
export * from './my-service.types';
export * from './my-component.types';
export * from './my-interfaces';

Step 3: Export from Library Root

// libs/my-library/src/lib/index.ts
export * from './models';        // ← Export models FIRST
export * from './services';
export * from './components';

Step 4: Import in Services/Components

// libs/my-library/src/lib/services/my-service.ts
import { Injectable } from '@angular/core';
import { MyServiceConfig, MyServiceState } from '../models';  // ← Import from models

@Injectable({ providedIn: 'root' })
export class MyService {
  private state: MyServiceState = {
    loading: false,
    error: null,
    data: []
  };
  
  configure(config: MyServiceConfig): void {
    // Implementation using imported types
  }
}

❌ Wrong Patterns to Avoid

❌ Local Type Definitions

// ❌ NEVER DO THIS: Local interface in service file
import { Injectable } from '@angular/core';

interface MyServiceConfig {  // ← DON'T DEFINE TYPES HERE!
  apiUrl: string;
}

@Injectable()
export class MyService {
  // ...
}

❌ Inline Type Definitions

// ❌ NEVER DO THIS: Inline types in components
@Component({...})
export class MyComponent {
  @Input() config!: {  // ← DON'T DEFINE TYPES INLINE!
    title: string;
    data: any;
  };
}

❌ Exporting Types from Services

// ❌ NEVER DO THIS: Exporting types from service files
export interface MyConfig { ... }  // ← DON'T EXPORT FROM SERVICES!

@Injectable()
export class MyService { ... }

🔧 Benefits of This Pattern

1. Prevents Build Issues

2. Promotes Code Reuse

3. Better Architecture

🎯 Real-World Examples

Example 1: UX Menu Library

// libs/ux-menu/src/lib/models/ux-menu.models.ts
export interface UxMenuItem {
  id: string;
  label: string;
  icon?: string;
  disabled?: boolean;
}

export interface UxMenuConfig {
  id: string;
  items: UxMenuItem[];
  theme?: string;
}
// libs/ux-menu/src/lib/services/ux-menu.service.ts
import { Injectable } from '@angular/core';
import { UxMenuItem, UxMenuConfig } from '../models';  // ← Import from models

@Injectable()
export class UxMenuService {
  private config: UxMenuConfig | null = null;
  
  setConfig(config: UxMenuConfig): void {
    this.config = config;
  }
}

Example 2: Storage Library

// libs/storage-system/src/lib/models/storage.types.ts
export interface StorageConfig {
  adapter: 'memory' | 'indexeddb' | 'localstorage';
  namespace: string;
  compression?: boolean;
}

export interface StorageItem<T = any> {
  key: string;
  value: T;
  timestamp: number;
}
// libs/storage-system/src/lib/services/storage.service.ts  
import { Injectable } from '@angular/core';
import { StorageConfig, StorageItem } from '../models';  // ← Import from models

@Injectable()
export class StorageService {
  private config: StorageConfig | null = null;
  
  async getItem<T>(key: string): Promise<StorageItem<T> | null> {
    // Implementation using imported types
  }
}

🚨 Common Build Error Solutions

Error: "Cannot destructure property 'pos'"

Cause: Local type definitions causing TypeScript compilation issues Solution: Move all types to models directory

// ❌ Before: Causes build errors
interface LocalType { ... }  // ← Problematic
export class MyService { ... }

// ✅ After: Fixes build errors
import { MyType } from '../models';  // ← From models directory
export class MyService { ... }

Error: "Comments in CSS use '/* ... */' instead of '//'"

Cause: Using JavaScript-style comments in CSS/SCSS files Solution: Use proper CSS comment syntax

/* ❌ Before: Causes CSS syntax errors */
// Enhanced Navigation Controls

/* ✅ After: Proper CSS comments */
/* Enhanced Navigation Controls */

Error: "Expected ':' [css-syntax-error]"

Cause: Extra characters in CSS properties Solution: Remove invalid characters

/* ❌ Before: Causes CSS syntax errors */
padding-top: 1rem;z

/* ✅ After: Clean CSS properties */
padding-top: 1rem;

Error: "Duplicate key in object literal"

Cause: Duplicate keys in package.json scripts Solution: Rename duplicate keys

{
  "//2.1": "=== DASHBOARD AUTO-RELOAD COMMANDS ===",
  "//2.2": "=== DASHBOARD AUTO-RELOAD COMMANDS ==="
}

Error: "Circular dependency detected"

Cause: Services importing/exporting types incorrectly Solution: Centralize all types in models directory

// ❌ Before: Circular dependencies
// service-a.ts exports types
// service-b.ts imports from service-a.ts
// service-a.ts imports from service-b.ts

// ✅ After: No circular dependencies
// models/index.ts exports all types
// service-a.ts imports from models
// service-b.ts imports from models

🔄 Migration Steps

If You Have Local Types in Existing Code:

  1. Create models directory:

    mkdir -p libs/my-library/src/lib/models
    
  2. Move all type definitions:

    // Cut from service files, paste into models/my-types.ts
    export interface MyType { ... }
    
  3. Create models index:

    // libs/my-library/src/lib/models/index.ts
    export * from './my-types';
    
  4. Update imports:

    // In service files, replace local types with:
    import { MyType } from '../models';
    
  5. Export from library root:

    // libs/my-library/src/lib/index.ts
    export * from './models';  // ← Add this first
    

✅ Checklist for New Libraries

📚 Related Documentation


Remember: This pattern is CRITICAL for preventing build issues and maintaining code quality. Always follow the "No Local Types" policy!