CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-tsyringe

Lightweight dependency injection container for JavaScript/TypeScript

Pending
Overview
Eval results
Files

providers.mddocs/

Provider System

Flexible provider system for registering dependencies using different patterns including class constructors, factory functions, concrete values, and token aliases. Includes comprehensive type guards for runtime provider type checking.

Capabilities

Provider Types

Union type encompassing all available provider patterns for maximum flexibility in dependency registration.

/**
 * Union type of all provider types
 * Enables flexible dependency registration patterns
 */
type Provider<T> = ClassProvider<T> | FactoryProvider<T> | ValueProvider<T> | TokenProvider<T>;

/**
 * Type guard to check if value is any provider type
 * @param provider - Value to check
 * @returns True if value is a provider
 */
function isProvider<T>(provider: any): provider is Provider<T>;

Usage Examples:

const classProvider: Provider<UserService> = { useClass: UserService };
const factoryProvider: Provider<Logger> = { 
  useFactory: (container) => new Logger(container.resolve("LogLevel"))
};

if (isProvider(someValue)) {
  container.register("Service", someValue);
}

Class Provider

Provider that uses a class constructor to create instances, supporting both regular constructors and delayed constructors for lazy loading.

/**
 * Provider using class constructor for instance creation
 * Supports both regular and delayed constructors
 */
interface ClassProvider<T> {
  useClass: constructor<T> | DelayedConstructor<T>;
}

/**
 * Type guard for class providers
 * @param provider - Provider to check
 * @returns True if provider is ClassProvider
 */
function isClassProvider<T>(provider: any): provider is ClassProvider<T>;

Usage Examples:

// Basic class provider
const userServiceProvider: ClassProvider<UserService> = {
  useClass: UserService
};

// With delayed constructor for circular dependencies
const delayedProvider: ClassProvider<CircularService> = {
  useClass: delay(() => CircularService)
};

container.register("UserService", userServiceProvider);

// Type guard usage
if (isClassProvider(provider)) {
  console.log("Using class:", provider.useClass.name);
}

Factory Provider

Provider that uses a factory function to create instances, providing access to the dependency container for complex construction logic.

/**
 * Provider using factory function for instance creation
 * Factory receives dependency container for complex construction
 */
interface FactoryProvider<T> {
  useFactory: (dependencyContainer: DependencyContainer) => T;
}

/**
 * Type guard for factory providers
 * @param provider - Provider to check
 * @returns True if provider is FactoryProvider
 */
function isFactoryProvider<T>(provider: any): provider is FactoryProvider<T>;

Usage Examples:

// Database connection factory
const dbProvider: FactoryProvider<Database> = {
  useFactory: (container) => {
    const config = container.resolve<DatabaseConfig>("DatabaseConfig");
    const logger = container.resolve<Logger>("Logger");
    return new Database(config.connectionString, logger);
  }
};

// Conditional factory
const loggerProvider: FactoryProvider<Logger> = {
  useFactory: (container) => {
    const env = container.resolve<string>("Environment");
    return env === "production" 
      ? new ProductionLogger() 
      : new DevelopmentLogger();
  }
};

container.register("Database", dbProvider);

if (isFactoryProvider(provider)) {
  const instance = provider.useFactory(container);
}

Value Provider

Provider that directly provides a concrete value or instance, useful for configuration objects, primitives, and pre-constructed instances.

/**
 * Provider using concrete value or pre-constructed instance
 * Perfect for configuration, primitives, and shared instances
 */
interface ValueProvider<T> {
  useValue: T;
}

/**
 * Type guard for value providers
 * @param provider - Provider to check  
 * @returns True if provider is ValueProvider
 */
function isValueProvider<T>(provider: any): provider is ValueProvider<T>;

Usage Examples:

// Configuration object
const configProvider: ValueProvider<AppConfig> = {
  useValue: {
    apiUrl: "https://api.example.com",
    timeout: 5000,
    retries: 3
  }
};

// Primitive values
const portProvider: ValueProvider<number> = {
  useValue: 8080
};

// Pre-constructed instance
const existingLogger = new Logger("app");
const loggerProvider: ValueProvider<Logger> = {
  useValue: existingLogger
};

container.register("AppConfig", configProvider);
container.register("Port", portProvider);

if (isValueProvider(provider)) {
  console.log("Direct value:", provider.useValue);
}

Token Provider

Provider that aliases one injection token to another, enabling interface-to-implementation mapping and token redirection.

/**
 * Provider that aliases one token to another
 * Enables interface-to-implementation mapping
 */
interface TokenProvider<T> {
  useToken: InjectionToken<T>;
}

/**
 * Type guard for token providers  
 * @param provider - Provider to check
 * @returns True if provider is TokenProvider
 */
function isTokenProvider<T>(provider: any): provider is TokenProvider<T>;

Usage Examples:

// Interface to implementation mapping
container.register("PostgresUserRepo", PostgresUserRepository);
const repoProvider: TokenProvider<IUserRepository> = {
  useToken: "PostgresUserRepo"
};
container.register("IUserRepository", repoProvider);

// Environment-based aliasing
const dbProvider: TokenProvider<IDatabase> = {
  useToken: process.env.NODE_ENV === "test" ? "MockDatabase" : "PostgresDatabase"
};

// Class token aliasing  
const serviceProvider: TokenProvider<IUserService> = {
  useToken: UserService
};

if (isTokenProvider(provider)) {
  console.log("Redirects to token:", provider.useToken);
}

Injection Token System

Comprehensive token system supporting multiple token types with utility functions for token type checking and metadata handling.

/**
 * Union type for all supported injection token types
 * Supports classes, strings, symbols, and delayed constructors
 */
type InjectionToken<T> = constructor<T> | string | symbol | DelayedConstructor<T>;

/**
 * Type guard for normal tokens (string | symbol)
 * @param token - Token to check
 * @returns True if token is string or symbol
 */
function isNormalToken(token: any): token is string | symbol;

/**
 * Type guard for constructor tokens
 * @param token - Token to check
 * @returns True if token is constructor function  
 */
function isConstructorToken(token: any): token is constructor<any>;

Usage Examples:

// Different token types
const stringToken: InjectionToken<UserService> = "UserService";
const symbolToken: InjectionToken<Logger> = Symbol("Logger");
const classToken: InjectionToken<Database> = Database;
const delayedToken: InjectionToken<CircularService> = delay(() => CircularService);

// Token checking
if (isNormalToken(token)) {
  console.log("String or symbol token:", token.toString());
}

if (isConstructorToken(token)) {
  console.log("Constructor token:", token.name);
}

// Registration with different token types
container.register(stringToken, UserService);
container.register(symbolToken, ConsoleLogger);
container.register(classToken, { useClass: PostgresDatabase });

Token Descriptors

Advanced token metadata system for complex injection scenarios with multiple dependencies and transformations.

/**
 * Token descriptor with metadata for complex injection
 * Used internally for parameter decoration metadata
 */
interface TokenDescriptor {
  token: InjectionToken<any>;
  multiple: boolean;
  isOptional?: boolean;
}

/**
 * Transform descriptor for parameter transformation
 * Contains transformation token and arguments
 */
interface TransformDescriptor {
  token: InjectionToken<any>;
  transform: InjectionToken<Transform<any, any>>;
  transformArgs: any[];
}

/**
 * Type guard for token descriptors
 * @param descriptor - Descriptor to check
 * @returns True if descriptor is TokenDescriptor
 */
function isTokenDescriptor(descriptor: any): descriptor is TokenDescriptor;

/**
 * Type guard for transform descriptors
 * @param descriptor - Descriptor to check  
 * @returns True if descriptor is TransformDescriptor
 */
function isTransformDescriptor(descriptor: any): descriptor is TransformDescriptor;

Usage Examples:

// Token descriptors are typically used internally
// but can be useful for advanced scenarios

const descriptor: TokenDescriptor = {
  token: "UserService",
  multiple: false,
  isOptional: true
};

const transformDescriptor: TransformDescriptor = {
  token: "ConfigValues",
  transform: "StringToNumberTransform",
  transformArgs: ["radix", 10]
};

// Type checking
if (isTokenDescriptor(someDescriptor)) {
  console.log("Token:", someDescriptor.token);
  console.log("Multiple:", someDescriptor.multiple);
}

if (isTransformDescriptor(someDescriptor)) {
  console.log("Transform token:", someDescriptor.transform);
  console.log("Transform args:", someDescriptor.transformArgs);
}

Types

// Core provider union type
type Provider<T> = ClassProvider<T> | FactoryProvider<T> | ValueProvider<T> | TokenProvider<T>;

// Individual provider interfaces
interface ClassProvider<T> {
  useClass: constructor<T> | DelayedConstructor<T>;
}

interface FactoryProvider<T> {
  useFactory: (dependencyContainer: DependencyContainer) => T;
}

interface ValueProvider<T> {
  useValue: T;
}

interface TokenProvider<T> {
  useToken: InjectionToken<T>;
}

// Token system types
type InjectionToken<T> = constructor<T> | string | symbol | DelayedConstructor<T>;

interface TokenDescriptor {
  token: InjectionToken<any>;
  multiple: boolean;
  isOptional?: boolean;
}

interface TransformDescriptor {
  token: InjectionToken<any>;
  transform: InjectionToken<Transform<any, any>>;
  transformArgs: any[];
}

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

// Transform interface
interface Transform<TIn, TOut> {
  transform(incoming: TIn, ...args: any[]): TOut;
}

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