Utils Package
The @repo/utils package contains shared utility functions and helpers used across the application.
Overview
This package provides common utilities for:
- String manipulation
- Date formatting
- Validation helpers
- Type guards
- Common algorithms
Structure
packages/utils/
├── src/
│ ├── string.ts # String utilities
│ ├── date.ts # Date utilities
│ ├── validation.ts # Validation helpers
│ ├── types.ts # Type utilities
│ ├── index.ts # Main exports
│ └── ...
│
├── package.json
└── tsconfig.jsonUtilities
String Utilities
typescript
// src/string.ts
/**
* Capitalize first letter of string
*/
export function capitalize(str: string): string {
if (!str) return "";
return str.charAt(0).toUpperCase() + str.slice(1);
}
/**
* Truncate string to specified length
*/
export function truncate(str: string, maxLength: number): string {
if (str.length <= maxLength) return str;
return str.slice(0, maxLength - 3) + "...";
}
/**
* Convert string to slug format
*/
export function slugify(str: string): string {
return str
.toLowerCase()
.replace(/[^\w\s-]/g, "")
.replace(/[\s_-]+/g, "-")
.replace(/^-+|-+$/g, "");
}
/**
* Parse initials from name
*/
export function getInitials(name: string): string {
return name
.split(" ")
.map((word) => word[0])
.join("")
.toUpperCase()
.slice(0, 2);
}Date Utilities
typescript
// src/date.ts
/**
* Format date to relative time (e.g., "2 hours ago")
*/
export function formatRelativeTime(date: Date): string {
const now = new Date();
const diffMs = now.getTime() - date.getTime();
const diffSecs = Math.floor(diffMs / 1000);
const diffMins = Math.floor(diffSecs / 60);
const diffHours = Math.floor(diffMins / 60);
const diffDays = Math.floor(diffHours / 24);
if (diffSecs < 60) return "just now";
if (diffMins < 60) return `${diffMins} minute${diffMins > 1 ? "s" : ""} ago`;
if (diffHours < 24) return `${diffHours} hour${diffHours > 1 ? "s" : ""} ago`;
if (diffDays < 7) return `${diffDays} day${diffDays > 1 ? "s" : ""} ago`;
return date.toLocaleDateString();
}
/**
* Check if date is in the past
*/
export function isPast(date: Date): boolean {
return date < new Date();
}
/**
* Check if date is in the future
*/
export function isFuture(date: Date): boolean {
return date > new Date();
}
/**
* Format date to ISO string (YYYY-MM-DD)
*/
export function toISODateString(date: Date): string {
return date.toISOString().split("T")[0];
}Validation Utilities
typescript
// src/validation.ts
/**
* Validate email format
*/
export function isValidEmail(email: string): boolean {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return emailRegex.test(email);
}
/**
* Validate URL format
*/
export function isValidUrl(url: string): boolean {
try {
new URL(url);
return true;
} catch {
return false;
}
}
/**
* Check if string is not empty
*/
export function isNotEmpty(str: string): boolean {
return str.trim().length > 0;
}
/**
* Validate password strength
*/
export function isStrongPassword(password: string): boolean {
// At least 8 characters, 1 uppercase, 1 lowercase, 1 number
return (
password.length >= 8 &&
/[A-Z]/.test(password) &&
/[a-z]/.test(password) &&
/[0-9]/.test(password)
);
}Type Guards
typescript
// src/types.ts
/**
* Check if value is defined (not null or undefined)
*/
export function isDefined<T>(value: T | null | undefined): value is T {
return value !== null && value !== undefined;
}
/**
* Check if value is a number
*/
export function isNumber(value: unknown): value is number {
return typeof value === "number" && !isNaN(value);
}
/**
* Check if value is a string
*/
export function isString(value: unknown): value is string {
return typeof value === "string";
}
/**
* Check if value is an object
*/
export function isObject(value: unknown): value is Record<string, unknown> {
return typeof value === "object" && value !== null && !Array.isArray(value);
}
/**
* Check if array is not empty
*/
export function isNonEmptyArray<T>(arr: T[]): arr is [T, ...T[]] {
return arr.length > 0;
}Array Utilities
typescript
// src/array.ts
/**
* Remove duplicates from array
*/
export function unique<T>(arr: T[]): T[] {
return [...new Set(arr)];
}
/**
* Group array by key
*/
export function groupBy<T, K extends keyof T>(
arr: T[],
key: K,
): Record<string, T[]> {
return arr.reduce(
(groups, item) => {
const groupKey = String(item[key]);
if (!groups[groupKey]) {
groups[groupKey] = [];
}
groups[groupKey].push(item);
return groups;
},
{} as Record<string, T[]>,
);
}
/**
* Chunk array into smaller arrays
*/
export function chunk<T>(arr: T[], size: number): T[][] {
const chunks: T[][] = [];
for (let i = 0; i < arr.length; i += size) {
chunks.push(arr.slice(i, i + size));
}
return chunks;
}
/**
* Sort array by property
*/
export function sortBy<T, K extends keyof T>(
arr: T[],
key: K,
order: "asc" | "desc" = "asc",
): T[] {
return [...arr].sort((a, b) => {
const aVal = a[key];
const bVal = b[key];
if (aVal < bVal) return order === "asc" ? -1 : 1;
if (aVal > bVal) return order === "asc" ? 1 : -1;
return 0;
});
}Object Utilities
typescript
// src/object.ts
/**
* Deep clone an object
*/
export function deepClone<T>(obj: T): T {
return JSON.parse(JSON.stringify(obj));
}
/**
* Pick specified keys from object
*/
export function pick<T, K extends keyof T>(obj: T, keys: K[]): Pick<T, K> {
const result = {} as Pick<T, K>;
keys.forEach((key) => {
if (key in obj) {
result[key] = obj[key];
}
});
return result;
}
/**
* Omit specified keys from object
*/
export function omit<T, K extends keyof T>(obj: T, keys: K[]): Omit<T, K> {
const result = { ...obj };
keys.forEach((key) => {
delete result[key];
});
return result as Omit<T, K>;
}
/**
* Check if object has property
*/
export function hasProperty<T extends object, K extends PropertyKey>(
obj: T,
key: K,
): obj is T & Record<K, unknown> {
return key in obj;
}Usage
typescript
// In frontend or backend
import {
capitalize,
truncate,
formatRelativeTime,
isValidEmail,
unique,
} from "@repo/utils";
// String manipulation
const title = capitalize("hello world"); // "Hello world"
const short = truncate("Long text here", 10); // "Long te..."
// Date formatting
const timeAgo = formatRelativeTime(new Date("2024-01-01")); // "2 days ago"
// Validation
if (isValidEmail(email)) {
// Valid email
}
// Array operations
const uniqueIds = unique([1, 2, 2, 3, 3, 3]); // [1, 2, 3]Best Practices
- Keep utilities pure - No side effects
- Add TypeScript types - Full type safety
- Document functions - JSDoc comments
- Test thoroughly - Unit tests for all utilities
- Keep it focused - One responsibility per function
- Export from index - Clean imports
Related Documentation
- Frontend Components - Using utils in frontend
- Backend Components - Using utils in backend