Domain Toolkit
Utility functions and helpers for the domain layer. This package contains utilities only, not validation.
Purpose
The toolkit provides pure utility functions for common operations like:
- String manipulation
- Date/time formatting
- Currency formatting
- URL parsing and manipulation
- Type guards and assertions
Important: For validation functions (e.g., isValidEmail, isValidUuid), use packages/domain/common/validation.ts instead.
Structure
toolkit/
├── formatting/ # Formatting utilities
│ ├── currency.ts # Currency formatting (e.g., formatCurrency)
│ ├── date.ts # Date formatting (e.g., formatDate, formatRelativeTime)
│ ├── phone.ts # Phone number formatting
│ └── text.ts # Text manipulation (e.g., truncate, capitalize)
│
├── typing/ # Type utilities
│ ├── assertions.ts # Type assertions (e.g., assertNonNull)
│ ├── guards.ts # Type guards (e.g., isString, isNumber)
│ └── helpers.ts # Type helper functions
│
└── validation/ # Validation utilities (NOT validation itself)
├── email.ts # Email utilities (getEmailDomain, normalizeEmail)
├── url.ts # URL utilities (ensureProtocol, getHostname)
├── string.ts # String utilities (isEmpty, hasMinLength)
└── helpers.ts # Validation helpers (sanitizePagination, isInRange)
Important Distinction: Validation vs Utilities
❌ Validation (NOT in toolkit)
Validation determines if input is valid or invalid:
// These are VALIDATION functions → Use common/validation.ts
isValidEmail(email) // Returns true/false
isValidUuid(id) // Returns true/false
isValidUrl(url) // Returns true/false
validateUrlOrThrow(url) // Throws if invalid
Location: packages/domain/common/validation.ts
✅ Utilities (IN toolkit)
Utilities transform, extract, or manipulate data:
// These are UTILITY functions → Use toolkit
getEmailDomain(email) // Extracts domain from email
normalizeEmail(email) // Lowercases and trims
ensureProtocol(url) // Adds https:// if missing
getHostname(url) // Extracts hostname
Location: packages/domain/toolkit/
Usage Examples
Formatting
import { formatCurrency, formatDate } from "@customer-portal/domain/toolkit/formatting";
const price = formatCurrency(1000, "JPY"); // "¥1,000"
const date = formatDate(new Date()); // "2025-10-08"
Type Guards
import { isString, isNumber } from "@customer-portal/domain/toolkit/typing";
if (isString(value)) {
// TypeScript knows value is string here
console.log(value.toUpperCase());
}
URL Utilities
import { ensureProtocol, getHostname } from "@customer-portal/domain/toolkit/validation/url";
const fullUrl = ensureProtocol("example.com"); // "https://example.com"
const host = getHostname("https://example.com/path"); // "example.com"
Email Utilities
import { getEmailDomain, normalizeEmail } from "@customer-portal/domain/toolkit/validation/email";
const domain = getEmailDomain("user@example.com"); // "example.com"
const normalized = normalizeEmail(" User@Example.COM "); // "user@example.com"
When to Use What
| Task | Use | Example |
|---|---|---|
| Validate email format | common/validation.ts |
isValidEmail(email) |
| Extract email domain | toolkit/validation/email.ts |
getEmailDomain(email) |
| Validate URL format | common/validation.ts |
isValidUrl(url) |
| Add protocol to URL | toolkit/validation/url.ts |
ensureProtocol(url) |
| Format currency | toolkit/formatting/currency.ts |
formatCurrency(amount, "JPY") |
| Format date | toolkit/formatting/date.ts |
formatDate(date) |
Best Practices
-
Use validation functions for validation
// ✅ Good import { isValidEmail } from "@customer-portal/domain/common/validation"; if (!isValidEmail(email)) throw new Error("Invalid email"); // ❌ Bad - don't write custom validation if (!email.includes("@")) throw new Error("Invalid email"); -
Use utility functions for transformations
// ✅ Good import { normalizeEmail } from "@customer-portal/domain/toolkit/validation/email"; const clean = normalizeEmail(email); // ❌ Bad - don't duplicate utility logic const clean = email.trim().toLowerCase(); -
Don't mix validation and utilities
// ❌ Bad - mixing concerns function processEmail(email: string) { if (!email.includes("@")) return null; // Validation return email.toLowerCase(); // Utility } // ✅ Good - separate concerns import { isValidEmail } from "@customer-portal/domain/common/validation"; import { normalizeEmail } from "@customer-portal/domain/toolkit/validation/email"; function processEmail(email: string) { if (!isValidEmail(email)) return null; return normalizeEmail(email); }
Migration Notes
If you're refactoring existing code:
- Validation functions → Move to
common/validation.ts - Utility functions → Keep in or move to
toolkit/ - Business logic → Move to domain-specific
validation.tsfiles
Related Documentation
- Validation Patterns Guide - How to implement validation
- Domain Layer Design - Overall domain architecture
- Common Validation - Validation functions
Questions?
If you're unsure whether something belongs in toolkit or common/validation:
-
Ask: "Does this determine if input is valid/invalid?"
- YES → It's validation → Use
common/validation.ts - NO → It's a utility → Use
toolkit/
- YES → It's validation → Use
-
Ask: "Does this transform or extract data?"
- YES → It's a utility → Use
toolkit/ - NO → Might be validation → Use
common/validation.ts
- YES → It's a utility → Use