Skip to content

TypeScript Support

@shermant/logger is built with TypeScript from the ground up, providing excellent type safety and IntelliSense support. This guide covers all TypeScript-specific features and usage patterns.

Type Safety

The library provides comprehensive type definitions for all APIs, ensuring compile-time safety and excellent developer experience.

Basic Type Safety

typescript
import { Logger, logger } from '@shermant/logger'

// All methods are fully typed
logger.info
  .prefix('string only') // ✅ string parameter
  .text('message') // ✅ string parameter
  .time(true) // ✅ boolean parameter
  .print() // ✅ no parameters

// TypeScript will catch errors
logger.info
  .prefix(123) // ❌ Type error: number not assignable to string
  .time('invalid') // ❌ Type error: string not assignable to boolean

Logger Instance Types

typescript
import { Logger, LoggerType } from '@shermant/logger'

// Logger instance type
const loggerInstance: Logger = Logger.info

// Method return types are properly typed
const withPrefix: Logger = logger.info.prefix('API')
const withText: Logger = withPrefix.text('Request completed')

Custom Type Definitions

Creating Custom Log Types

The library provides type-safe ways to create custom log types:

typescript
import { LoggerType, logger } from '@shermant/logger'

// Define custom type with proper typing
interface CustomLogTypes {
  security: LoggerType.CreateCustomType
  performance: LoggerType.CreateCustomType
  audit: LoggerType.CreateCustomType
}

// Create logger with custom types
const customLogger = logger.createLogger<CustomLogTypes>()

// Use custom types with full type safety
customLogger
  .security(['bgRed', 'bold', 'white'])
  .prefix('🔒 SECURITY')
  .text('Authentication failed')
  .print()

customLogger
  .performance(['bgYellow', 'black'])
  .prefix('⚡ PERF')
  .text('Slow operation detected')
  .print()

Style Type Definitions

typescript
import { LoggerType } from '@shermant/logger'

// Style types are based on Chalk.js
type ValidStyles = LoggerType.Style[]

const redBackground: ValidStyles = ['bgRed', 'white']
const boldText: ValidStyles = ['bold', 'underline']
const coloredText: ValidStyles = ['blue', 'italic']

// Use with type safety
logger.type('custom', redBackground)
  .text('Styled message')
  .print()

Interface Definitions

Core Interfaces

typescript
// Logger interface
interface Logger {
  // Predefined log types
  info: Logger
  warn: Logger
  error: Logger
  debug: Logger
  success: Logger
  failure: Logger
  plain: Logger

  // Configuration methods
  prefix: (text: string) => Logger
  text: (message: string) => Logger
  detail: (detail: string) => Logger
  data: (data: any) => Logger
  time: (show?: boolean) => Logger

  // Styling methods
  style: (styles: LoggerType.Style[]) => Logger
  type: (name: string, styles?: LoggerType.Style[]) => Logger

  // Output methods
  print: (condition?: boolean) => void
  divider: (char?: string, length?: number) => void

  // Utility methods
  prependDivider: (char?: string, length?: number) => Logger
  appendDivider: (char?: string, length?: number) => Logger
}

// Stream Logger interface
interface StreamLogger {
  prefix: (text: string) => StreamLogger
  text: (message: string) => StreamLogger
  detail: (detail: string) => StreamLogger
  style: (styles: LoggerType.Style[]) => StreamLogger

  // Stream-specific methods
  update: () => StreamLogger
  state: (state: 'start' | 'stop' | 'succeed' | 'fail') => StreamLogger
  delay: (ms: number) => StreamLogger
}

Type Namespace

typescript
namespace LoggerType {
  // Style types from Chalk.js
  type Style =
    | 'reset' | 'bold' | 'dim' | 'italic' | 'underline' | 'inverse'
    | 'hidden' | 'strikethrough' | 'visible'
    | 'black' | 'red' | 'green' | 'yellow' | 'blue' | 'magenta' | 'cyan' | 'white'
    | 'gray' | 'grey' | 'blackBright' | 'redBright' | 'greenBright'
    | 'yellowBright' | 'blueBright' | 'magentaBright' | 'cyanBright' | 'whiteBright'
    | 'bgBlack' | 'bgRed' | 'bgGreen' | 'bgYellow' | 'bgBlue' | 'bgMagenta'
    | 'bgCyan' | 'bgWhite' | 'bgGray' | 'bgGrey' | 'bgBlackBright'
    | 'bgRedBright' | 'bgGreenBright' | 'bgYellowBright' | 'bgBlueBright'
    | 'bgMagentaBright' | 'bgCyanBright' | 'bgWhiteBright'

  type Styles = Style[]

  // Custom type creation
  type CreateCustomType = (styles: Styles) => Logger

  // Log levels
  type LogLevel = 'info' | 'warn' | 'error' | 'debug' | 'success' | 'failure' | 'plain'

  // Stream states
  type StreamState = 'start' | 'stop' | 'succeed' | 'fail'
}

Advanced TypeScript Features

Generic Type Support

typescript
import { logger } from '@shermant/logger'

// Generic data logging with type safety
interface UserData {
  id: number
  name: string
  email: string
}

interface ApiResponse<T> {
  data: T
  status: number
  message: string
}

function logApiResponse<T>(response: ApiResponse<T>) {
  logger.info
    .prefix('📡 API')
    .text('Response received')
    .detail(`Status: ${response.status}`)
    .detail(`Message: ${response.message}`)
    .data(response.data) // T is properly typed
    .print()
}

// Usage with type safety
const userResponse: ApiResponse<UserData> = {
  data: { id: 1, name: 'John', email: 'john@example.com' },
  status: 200,
  message: 'Success'
}

logApiResponse(userResponse) // ✅ Fully typed

Conditional Types

typescript
import { LoggerType, logger } from '@shermant/logger'

// Conditional logging based on environment
type LoggerConfig<T extends 'development' | 'production'> = T extends 'development'
  ? { verbose: true, colors: true }
  : { verbose: false, colors: false }

function createEnvironmentLogger<T extends 'development' | 'production'>(
  env: T,
  config: LoggerConfig<T>
) {
  if (config.verbose) {
    return logger.debug // Development logger
  }
  return logger.info // Production logger
}

// Type-safe environment logging
const devLogger = createEnvironmentLogger('development', { verbose: true, colors: true })
const prodLogger = createEnvironmentLogger('production', { verbose: false, colors: false })

Utility Types

typescript
import { Logger, LoggerType } from '@shermant/logger'

// Extract log level from logger instance
type ExtractLogLevel<T> = T extends Logger ? LoggerType.LogLevel : never

// Create logger factory with specific types
type LoggerFactory<T extends Record<string, LoggerType.CreateCustomType>> = {
  [K in keyof T]: T[K]
} & Logger

// Helper type for style validation
type ValidateStyles<T extends LoggerType.Style[]> = T

// Usage
const validStyles: ValidateStyles<['bgBlue', 'white']> = ['bgBlue', 'white'] // ✅
// const invalidStyles: ValidateStyles<['invalid']> = ['invalid']  // ❌ Type error

Type Guards and Validation

Runtime Type Checking

typescript
import { logger } from '@shermant/logger'

// Type guard for log data
function isValidLogData(data: unknown): data is Record<string, any> {
  return typeof data === 'object' && data !== null
}

// Safe logging with type guards
function safeLog(message: string, data?: unknown) {
  const logInstance = logger.info.text(message)

  if (data !== undefined && isValidLogData(data)) {
    logInstance.data(data).print()
  }
  else {
    logInstance.print()
  }
}

// Usage
safeLog('User created', { id: 1, name: 'John' }) // ✅ Valid data
safeLog('Simple message') // ✅ No data
safeLog('Invalid data', 'string') // ✅ Handled safely

Environment Type Detection

typescript
import { logger } from '@shermant/logger'

// Environment detection with types
type Environment = 'browser' | 'node' | 'bun' | 'unknown'

function detectEnvironment(): Environment {
  if (typeof window !== 'undefined')
    return 'browser'
  if (typeof process !== 'undefined' && process.versions?.node)
    return 'node'
  if (typeof process !== 'undefined' && process.versions?.bun)
    return 'bun'
  return 'unknown'
}

// Environment-specific logging
function logWithEnvironment(message: string) {
  const env = detectEnvironment()

  logger.info
    .prefix(`🌍 ${env.toUpperCase()}`)
    .text(message)
    .detail(`Environment: ${env}`)
    .print()
}

Express.js with TypeScript

typescript
import express, { NextFunction, Request, Response } from 'express'
import { logger } from '@shermant/logger'

interface LoggedRequest extends Request {
  startTime: number
}

// Typed middleware
function loggingMiddleware(req: LoggedRequest, res: Response, next: NextFunction) {
  req.startTime = Date.now()

  logger.info
    .prefix('📡 REQUEST')
    .text(`${req.method} ${req.path}`)
    .detail(`IP: ${req.ip}`)
    .time()
    .print()

  next()
}

// Typed error handler
function errorHandler(err: Error, req: Request, res: Response, next: NextFunction) {
  logger.error
    .prefix('❌ ERROR')
    .text('Request failed')
    .detail(`Route: ${req.path}`)
    .detail(`Error: ${err.message}`)
    .data({ stack: err.stack })
    .print()

  res.status(500).json({ error: 'Internal server error' })
}

NestJS Integration

typescript
import { Injectable, Logger as NestLogger } from '@nestjs/common'
import { logger } from '@shermant/logger'

@Injectable()
export class CustomLoggerService {
  private readonly logger = new NestLogger(CustomLoggerService.name)

  log(message: string, context?: string) {
    logger.info
      .prefix(context || 'APP')
      .text(message)
      .time()
      .print()
  }

  error(message: string, trace?: string, context?: string) {
    logger.error
      .prefix(context || 'ERROR')
      .text(message)
      .detail(trace || 'No stack trace')
      .time()
      .print()
  }

  warn(message: string, context?: string) {
    logger.warn
      .prefix(context || 'WARN')
      .text(message)
      .time()
      .print()
  }
}

Best Practices

Type-Safe Configuration

typescript
import { LoggerType, logger } from '@shermant/logger'

// Configuration interface
interface LoggerConfiguration {
  level: LoggerType.LogLevel
  prefix: string
  showTime: boolean
  styles: LoggerType.Style[]
}

// Factory function with type safety
function createConfiguredLogger(config: LoggerConfiguration) {
  return logger
    .type(config.level, config.styles)
    .prefix(config.prefix)
    .time(config.showTime)
}

// Usage with type safety
const apiLogger = createConfiguredLogger({
  level: 'info',
  prefix: '📡 API',
  showTime: true,
  styles: ['bgBlue', 'white']
})

Strict Type Checking

typescript
// Enable strict mode in tsconfig.json
{
  "compilerOptions": {
    "strict": true,
    "noImplicitAny": true,
    "strictNullChecks": true,
    "strictFunctionTypes": true
  }
}

// All logger usage will be strictly typed
import { logger } from '@shermant/logger'

// This will work with strict typing
logger.info
  .prefix('STRICT')      // string required
  .text('message')       // string required
  .time(true)           // boolean required
  .print()              // no parameters

The TypeScript support in @shermant/logger ensures that you get the best possible developer experience with full type safety, excellent IntelliSense, and compile-time error checking.

Released under the ISC License.