CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-tsyringe

Lightweight dependency injection container for JavaScript/TypeScript

Pending
Overview
Eval results
Files

factories.mddocs/

Factory Functions

Advanced factory utilities for creating sophisticated dependency construction patterns with caching strategies, conditional instantiation, and performance optimization.

Capabilities

Factory Function Type

Base factory function signature used throughout the factory system.

/**
 * Factory function signature for creating instances
 * Receives dependency container for accessing other dependencies
 * @param dependencyContainer - Container for resolving dependencies
 * @returns Instance of type T
 */
type FactoryFunction<T> = (dependencyContainer: DependencyContainer) => T;

Usage Examples:

// Basic factory function
const loggerFactory: FactoryFunction<Logger> = (container) => {
  const config = container.resolve<LogConfig>("LogConfig");
  return new Logger(config.level, config.format);
};

// Complex factory with multiple dependencies
const databaseFactory: FactoryFunction<Database> = (container) => {
  const config = container.resolve<DatabaseConfig>("DatabaseConfig");
  const logger = container.resolve<Logger>("Logger");
  const connectionPool = container.resolve<ConnectionPool>("ConnectionPool");
  
  const db = new Database(config.connectionString);
  db.setLogger(logger);
  db.setConnectionPool(connectionPool);
  
  return db;
};

// Register factory
container.register("Database", { useFactory: databaseFactory });

Global Instance Caching

Factory wrapper that caches instances globally across all containers and resolution calls.

/**
 * Creates factory that caches instance globally
 * Instance is shared across all containers and resolution calls
 * Perfect for expensive-to-create singletons
 * @param factoryFunc - Base factory function to wrap
 * @returns Cached factory function
 */
function instanceCachingFactory<T>(factoryFunc: FactoryFunction<T>): FactoryFunction<T>;

Usage Examples:

// Expensive service that should be created only once globally
const expensiveServiceFactory: FactoryFunction<ExpensiveService> = (container) => {
  console.log("Creating expensive service (this should only happen once)");
  const config = container.resolve<ServiceConfig>("ServiceConfig");
  return new ExpensiveService(config);
};

// Wrap with global caching
const cachedFactory = instanceCachingFactory(expensiveServiceFactory);

// Register cached factory
container.register("ExpensiveService", { useFactory: cachedFactory });

// Multiple containers share same instance
const container1 = container.createChildContainer();
const container2 = container.createChildContainer();

const service1 = container1.resolve<ExpensiveService>("ExpensiveService");
const service2 = container2.resolve<ExpensiveService>("ExpensiveService");
// service1 === service2 (same instance)

// Configuration service example
const configFactory = instanceCachingFactory<Configuration>((container) => {
  console.log("Loading configuration from file...");
  return Configuration.loadFromFile("./config.json");
});

container.register("Configuration", { useFactory: configFactory });

Container-Scoped Caching

Factory wrapper that caches instances per container, allowing different instances in child containers while maintaining caching within each container scope.

/**
 * Creates factory that caches instance per container
 * Each container maintains its own cached instance
 * Child containers can have different instances than parents
 * @param factoryFunc - Base factory function to wrap
 * @returns Per-container cached factory function
 */
function instancePerContainerCachingFactory<T>(factoryFunc: FactoryFunction<T>): FactoryFunction<T>;

Usage Examples:

// Request context that should be unique per container (e.g., per HTTP request)
const requestContextFactory: FactoryFunction<RequestContext> = (container) => {
  console.log("Creating request context for container");
  const requestId = container.resolve<string>("RequestId");
  const userId = container.resolve<string>("UserId");
  return new RequestContext(requestId, userId);
};

// Wrap with per-container caching
const perContainerCachedFactory = instancePerContainerCachingFactory(requestContextFactory);

container.register("RequestContext", { useFactory: perContainerCachedFactory });

// Parent container has one instance
const parentContext = container.resolve<RequestContext>("RequestContext");
const sameParentContext = container.resolve<RequestContext>("RequestContext");
// parentContext === sameParentContext

// Child containers have their own instances
const childContainer1 = container.createChildContainer();
const childContainer2 = container.createChildContainer();

const child1Context = childContainer1.resolve<RequestContext>("RequestContext");
const child2Context = childContainer2.resolve<RequestContext>("RequestContext");
// child1Context !== child2Context !== parentContext

// Database connection pool per environment
const dbPoolFactory = instancePerContainerCachingFactory<ConnectionPool>((container) => {
  const env = container.resolve<string>("Environment");
  console.log(`Creating connection pool for ${env}`);
  return new ConnectionPool(`db-${env}.example.com`);
});

container.register("ConnectionPool", { useFactory: dbPoolFactory });

Predicate-Aware Class Factory

Advanced factory that conditionally chooses between different constructors based on runtime conditions, with optional caching support.

/**
 * Creates factory that chooses constructor based on predicate
 * Enables conditional instantiation patterns
 * @param predicate - Function determining which constructor to use
 * @param trueConstructor - Constructor used when predicate returns true
 * @param falseConstructor - Constructor used when predicate returns false
 * @param useCaching - Whether to cache instances (default: false)
 * @returns Conditional factory function
 */
function predicateAwareClassFactory<T>(
  predicate: (dependencyContainer: DependencyContainer) => boolean,
  trueConstructor: constructor<T>,
  falseConstructor: constructor<T>,
  useCaching?: boolean
): FactoryFunction<T>;

Usage Examples:

// Environment-based service selection
const isProduction = (container: DependencyContainer) => {
  const env = container.resolve<string>("Environment");
  return env === "production";
};

const loggerFactory = predicateAwareClassFactory(
  isProduction,
  ProductionLogger,  // Use in production
  DevelopmentLogger, // Use in development
  true // Cache the instance
);

container.register("Logger", { useFactory: loggerFactory });

// Feature flag based implementation
const hasFeatureFlag = (container: DependencyContainer) => {
  const featureFlags = container.resolve<FeatureFlags>("FeatureFlags");
  return featureFlags.isEnabled("new-payment-processor");
};

const paymentProcessorFactory = predicateAwareClassFactory(
  hasFeatureFlag,
  NewPaymentProcessor,
  LegacyPaymentProcessor
);

container.register("PaymentProcessor", { useFactory: paymentProcessorFactory });

// Configuration-based repository selection
const usePostgres = (container: DependencyContainer) => {
  const dbConfig = container.resolve<DatabaseConfig>("DatabaseConfig");
  return dbConfig.type === "postgresql";
};

const userRepositoryFactory = predicateAwareClassFactory(
  usePostgres,
  PostgresUserRepository,
  MongoUserRepository,
  true // Cache for performance
);

container.register("UserRepository", { useFactory: userRepositoryFactory });

// A/B testing implementation selection
const isTestGroupA = (container: DependencyContainer) => {
  const userId = container.resolve<string>("UserId");
  const hash = simpleHash(userId);
  return hash % 2 === 0; // 50/50 split
};

const analyticsFactory = predicateAwareClassFactory(
  isTestGroupA,
  EnhancedAnalytics,
  StandardAnalytics
);

container.register("Analytics", { useFactory: analyticsFactory });

Complex Factory Combinations

Examples of combining multiple factory patterns for sophisticated dependency management.

Usage Examples:

// Cached conditional factory
const cachedConditionalLogger = instanceCachingFactory(
  predicateAwareClassFactory(
    (container) => container.resolve<string>("LogLevel") === "debug",
    DebugLogger,
    ProductionLogger,
    false // Don't double-cache at predicate level
  )
);

container.register("Logger", { useFactory: cachedConditionalLogger });

// Per-container cached conditional database
const perContainerDbFactory = instancePerContainerCachingFactory(
  predicateAwareClassFactory(
    (container) => {
      try {
        const testMode = container.resolve<boolean>("TestMode");
        return testMode;
      } catch {
        return false;
      }
    },
    InMemoryDatabase,
    PostgresDatabase,
    false // Caching handled at container level
  )
);

container.register("Database", { useFactory: perContainerDbFactory });

// Multi-condition factory
const multiConditionFactory: FactoryFunction<NotificationService> = (container) => {
  const env = container.resolve<string>("Environment");
  const features = container.resolve<FeatureFlags>("FeatureFlags");
  
  if (env === "test") {
    return new MockNotificationService();
  }
  
  if (features.isEnabled("push-notifications")) {
    return new PushNotificationService(
      container.resolve("PushConfig")
    );
  }
  
  return new EmailNotificationService(
    container.resolve("EmailConfig")
  );
};

container.register("NotificationService", { 
  useFactory: instanceCachingFactory(multiConditionFactory)
});

Types

// Core factory function type
type FactoryFunction<T> = (dependencyContainer: DependencyContainer) => T;

// Constructor type for predicate-aware factories
type constructor<T> = {new (...args: any[]): T};

// Predicate function type
type PredicateFunction = (dependencyContainer: DependencyContainer) => boolean;

// Factory wrapper function types
type CachingFactoryWrapper<T> = (factoryFunc: FactoryFunction<T>) => FactoryFunction<T>;

type ConditionalFactoryBuilder<T> = (
  predicate: PredicateFunction,
  trueConstructor: constructor<T>,
  falseConstructor: constructor<T>,
  useCaching?: boolean
) => FactoryFunction<T>;

Install with Tessl CLI

npx tessl i tessl/npm-tsyringe

docs

decorators.md

dependency-container.md

factories.md

index.md

lazy-loading.md

lifecycle-management.md

providers.md

tile.json