Prerequisites
- Understanding of TypeScript declaration files and ambient declarations 📝
- Knowledge of JavaScript global objects and scope ⚡
- Familiarity with module systems and namespace merging 💻
What you'll learn
- Master global augmentation syntax and advanced techniques 🎯
- Safely extend built-in global objects and interfaces 🏗️
- Create powerful development tools and utilities 🐛
- Implement type-safe global enhancements without conflicts ✨
🎯 Introduction
Welcome to the cosmic command center of TypeScript! 🌍 If regular TypeScript development were like having your own personal workspace, then global augmentation is like having the power to enhance the entire universe - you can add new capabilities to the fundamental building blocks of JavaScript, extend global objects, and create utilities that are available everywhere in your application!
Global augmentation allows you to extend existing global interfaces, add new properties to built-in objects, and enhance the global scope with custom functionality. This powerful feature is particularly useful for creating development tools, polyfills, library enhancements, and application-wide utilities while maintaining full type safety.
By the end of this tutorial, you’ll be a global augmentation expert, capable of safely and effectively extending the global scope to create powerful, type-safe enhancements that elevate your entire development experience. Let’s explore the art of global enhancement! 🌟
📚 Understanding Global Augmentation
🤔 What Is Global Augmentation?
Global augmentation is the process of extending existing global interfaces or adding new declarations to the global scope. It allows you to enhance built-in objects, create global utilities, and extend third-party library types while maintaining TypeScript’s type safety.
// 🌟 Basic global augmentation examples
// Extending the global Window interface
declare global {
interface Window {
myCustomProperty: string;
myUtilityFunction: (value: string) => string;
appConfig: AppConfiguration;
}
}
// Now you can use these properties with full type safety
window.myCustomProperty = 'Hello, World!';
window.myUtilityFunction = (value: string) => value.toUpperCase();
window.appConfig = {
apiUrl: 'https://api.example.com',
version: '1.0.0'
};
interface AppConfiguration {
apiUrl: string;
version: string;
features?: string[];
}
// 🎯 Extending built-in JavaScript objects
declare global {
interface Array<T> {
// Add a custom method to all arrays
findLast(predicate: (value: T, index: number, array: T[]) => boolean): T | undefined;
// Add a utility method for chunking arrays
chunk(size: number): T[][];
// Add a method for removing duplicates
unique(): T[];
}
interface String {
// Add string utility methods
capitalize(): string;
truncate(length: number, suffix?: string): string;
isEmail(): boolean;
toKebabCase(): string;
}
interface Number {
// Add number utility methods
toHumanReadable(): string;
clamp(min: number, max: number): number;
isInRange(min: number, max: number): boolean;
}
interface Date {
// Add date utility methods
toRelativeString(): string;
addDays(days: number): Date;
isWeekend(): boolean;
formatAs(format: string): string;
}
}
// ✨ Implementing the augmented methods
// (Note: In real applications, these would be in separate implementation files)
// Array extensions implementation
Array.prototype.findLast = function<T>(
this: T[],
predicate: (value: T, index: number, array: T[]) => boolean
): T | undefined {
for (let i = this.length - 1; i >= 0; i--) {
if (predicate(this[i], i, this)) {
return this[i];
}
}
return undefined;
};
Array.prototype.chunk = function<T>(this: T[], size: number): T[][] {
const chunks: T[][] = [];
for (let i = 0; i < this.length; i += size) {
chunks.push(this.slice(i, i + size));
}
return chunks;
};
Array.prototype.unique = function<T>(this: T[]): T[] {
return [...new Set(this)];
};
// String extensions implementation
String.prototype.capitalize = function(this: string): string {
return this.charAt(0).toUpperCase() + this.slice(1).toLowerCase();
};
String.prototype.truncate = function(
this: string,
length: number,
suffix: string = '...'
): string {
return this.length > length ? this.slice(0, length) + suffix : this.toString();
};
String.prototype.isEmail = function(this: string): boolean {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return emailRegex.test(this);
};
String.prototype.toKebabCase = function(this: string): string {
return this
.replace(/([a-z])([A-Z])/g, '$1-$2')
.replace(/[\s_]+/g, '-')
.toLowerCase();
};
// Number extensions implementation
Number.prototype.toHumanReadable = function(this: number): string {
const num = this.valueOf();
if (num >= 1e9) return (num / 1e9).toFixed(1) + 'B';
if (num >= 1e6) return (num / 1e6).toFixed(1) + 'M';
if (num >= 1e3) return (num / 1e3).toFixed(1) + 'K';
return num.toString();
};
Number.prototype.clamp = function(this: number, min: number, max: number): number {
return Math.min(Math.max(this.valueOf(), min), max);
};
Number.prototype.isInRange = function(
this: number,
min: number,
max: number
): boolean {
const num = this.valueOf();
return num >= min && num <= max;
};
// Date extensions implementation
Date.prototype.toRelativeString = function(this: Date): string {
const now = new Date();
const diffMs = now.getTime() - this.getTime();
const diffMins = Math.floor(diffMs / (1000 * 60));
const diffHours = Math.floor(diffMins / 60);
const diffDays = Math.floor(diffHours / 24);
if (diffMins < 1) return 'just now';
if (diffMins < 60) return `${diffMins} minute${diffMins !== 1 ? 's' : ''} ago`;
if (diffHours < 24) return `${diffHours} hour${diffHours !== 1 ? 's' : ''} ago`;
return `${diffDays} day${diffDays !== 1 ? 's' : ''} ago`;
};
Date.prototype.addDays = function(this: Date, days: number): Date {
const result = new Date(this);
result.setDate(result.getDate() + days);
return result;
};
Date.prototype.isWeekend = function(this: Date): boolean {
const day = this.getDay();
return day === 0 || day === 6; // Sunday or Saturday
};
Date.prototype.formatAs = function(this: Date, format: string): string {
const map: Record<string, string> = {
'yyyy': this.getFullYear().toString(),
'MM': (this.getMonth() + 1).toString().padStart(2, '0'),
'dd': this.getDate().toString().padStart(2, '0'),
'HH': this.getHours().toString().padStart(2, '0'),
'mm': this.getMinutes().toString().padStart(2, '0'),
'ss': this.getSeconds().toString().padStart(2, '0')
};
return format.replace(/yyyy|MM|dd|HH|mm|ss/g, match => map[match]);
};
// 🎮 Now you can use the extended functionality with full type safety!
console.log('🌍 Global Augmentation Examples');
// Array extensions in action
const numbers = [1, 2, 3, 4, 5, 4, 3, 2, 1];
const lastEven = numbers.findLast(n => n % 2 === 0);
const chunks = numbers.chunk(3);
const uniqueNumbers = numbers.unique();
console.log('📊 Array extensions:', { lastEven, chunks, uniqueNumbers });
// String extensions in action
const text = 'hello world';
const email = '[email protected]';
const longText = 'This is a very long string that needs truncation';
console.log('📝 String extensions:', {
capitalized: text.capitalize(),
isValidEmail: email.isEmail(),
truncated: longText.truncate(20),
kebabCase: 'CamelCaseString'.toKebabCase()
});
// Number extensions in action
const largeNumber = 1234567;
const value = 15;
console.log('🔢 Number extensions:', {
humanReadable: largeNumber.toHumanReadable(),
clamped: value.clamp(10, 20),
inRange: value.isInRange(10, 20)
});
// Date extensions in action
const now = new Date();
const pastDate = new Date(Date.now() - 2 * 60 * 60 * 1000); // 2 hours ago
const futureDate = now.addDays(7);
console.log('📅 Date extensions:', {
relative: pastDate.toRelativeString(),
futureDate: futureDate.formatAs('yyyy-MM-dd'),
isWeekend: now.isWeekend()
});
// 🏗️ Advanced global augmentation patterns
declare global {
// 🌐 Global namespace for application utilities
namespace App {
interface Config {
apiUrl: string;
version: string;
environment: 'development' | 'staging' | 'production';
features: FeatureFlags;
}
interface FeatureFlags {
enableBetaFeatures: boolean;
enableAnalytics: boolean;
enableDarkMode: boolean;
maxFileUploadSize: number;
}
interface User {
id: string;
name: string;
email: string;
roles: Role[];
preferences: UserPreferences;
}
interface Role {
id: string;
name: string;
permissions: Permission[];
}
interface Permission {
resource: string;
actions: string[];
}
interface UserPreferences {
theme: 'light' | 'dark' | 'auto';
language: string;
timezone: string;
notifications: NotificationSettings;
}
interface NotificationSettings {
email: boolean;
push: boolean;
inApp: boolean;
}
// Global utility functions interface
interface Utils {
logger: Logger;
storage: Storage;
http: HttpClient;
events: EventEmitter;
validation: Validator;
}
interface Logger {
debug(message: string, ...args: any[]): void;
info(message: string, ...args: any[]): void;
warn(message: string, ...args: any[]): void;
error(message: string, ...args: any[]): void;
}
interface Storage {
get<T>(key: string): T | null;
set<T>(key: string, value: T): void;
remove(key: string): void;
clear(): void;
}
interface HttpClient {
get<T>(url: string, options?: RequestOptions): Promise<T>;
post<T>(url: string, data?: any, options?: RequestOptions): Promise<T>;
put<T>(url: string, data?: any, options?: RequestOptions): Promise<T>;
delete<T>(url: string, options?: RequestOptions): Promise<T>;
}
interface RequestOptions {
headers?: Record<string, string>;
timeout?: number;
retries?: number;
}
interface EventEmitter {
on<T>(event: string, handler: (data: T) => void): void;
off(event: string, handler?: Function): void;
emit<T>(event: string, data?: T): void;
}
interface Validator {
isEmail(value: string): boolean;
isUrl(value: string): boolean;
isPhoneNumber(value: string): boolean;
isStrongPassword(value: string): boolean;
validateSchema<T>(value: any, schema: ValidationSchema): T;
}
interface ValidationSchema {
[key: string]: {
type: 'string' | 'number' | 'boolean' | 'object' | 'array';
required?: boolean;
min?: number;
max?: number;
pattern?: RegExp;
validator?: (value: any) => boolean;
};
}
}
// 🔧 Global application instance
var app: {
config: App.Config;
user: App.User | null;
utils: App.Utils;
version: string;
initialized: boolean;
};
// 🎯 Global functions
function logDebug(message: string, ...args: any[]): void;
function logInfo(message: string, ...args: any[]): void;
function logWarn(message: string, ...args: any[]): void;
function logError(message: string, ...args: any[]): void;
// 🚀 Performance and monitoring globals
function trackEvent(eventName: string, properties?: Record<string, any>): void;
function trackError(error: Error, context?: Record<string, any>): void;
function measurePerformance<T>(name: string, fn: () => T): T;
function measureAsyncPerformance<T>(name: string, fn: () => Promise<T>): Promise<T>;
// 🔒 Security and validation globals
function sanitizeHtml(html: string): string;
function validateCsrf(token: string): boolean;
function hashPassword(password: string): string;
function verifyPassword(password: string, hash: string): boolean;
}
// 🎮 Let's create a comprehensive global augmentation management system
namespace GlobalAugmentationManager {
// 📊 Track global augmentations
export interface AugmentationInfo {
target: string;
properties: AugmentedProperty[];
source: string;
version: string;
description: string;
dependencies: string[];
}
export interface AugmentedProperty {
name: string;
type: 'method' | 'property' | 'getter' | 'setter';
signature?: string;
description?: string;
examples?: string[];
}
export interface GlobalRegistry {
augmentations: Map<string, AugmentationInfo>;
conflicts: ConflictInfo[];
usage: Map<string, UsageStats>;
}
export interface ConflictInfo {
target: string;
property: string;
conflictingAugmentations: string[];
severity: 'warning' | 'error';
}
export interface UsageStats {
callCount: number;
lastUsed: Date;
averageExecutionTime: number;
errorCount: number;
}
// 🏗️ Global augmentation registry
const globalRegistry: GlobalRegistry = {
augmentations: new Map(),
conflicts: [],
usage: new Map()
};
// 📝 Register global augmentation
export function registerAugmentation(info: AugmentationInfo): void {
console.log(`📝 Registering global augmentation: ${info.target}`);
// 🔍 Check for conflicts
const existingAugmentation = globalRegistry.augmentations.get(info.target);
if (existingAugmentation) {
const conflicts = detectConflicts(existingAugmentation, info);
if (conflicts.length > 0) {
globalRegistry.conflicts.push(...conflicts);
console.warn(`⚠️ Conflicts detected for ${info.target}:`, conflicts);
}
}
globalRegistry.augmentations.set(info.target, info);
initializeUsageTracking(info);
}
// 🔍 Detect conflicts between augmentations
function detectConflicts(
existing: AugmentationInfo,
newAug: AugmentationInfo
): ConflictInfo[] {
const conflicts: ConflictInfo[] = [];
existing.properties.forEach(existingProp => {
const conflictingProp = newAug.properties.find(
newProp => newProp.name === existingProp.name
);
if (conflictingProp) {
conflicts.push({
target: existing.target,
property: existingProp.name,
conflictingAugmentations: [existing.source, newAug.source],
severity: existingProp.type !== conflictingProp.type ? 'error' : 'warning'
});
}
});
return conflicts;
}
// 📊 Initialize usage tracking
function initializeUsageTracking(info: AugmentationInfo): void {
info.properties.forEach(prop => {
const key = `${info.target}.${prop.name}`;
globalRegistry.usage.set(key, {
callCount: 0,
lastUsed: new Date(),
averageExecutionTime: 0,
errorCount: 0
});
});
}
// 📈 Track usage of augmented methods
export function trackUsage(
target: string,
property: string,
executionTime: number,
hadError: boolean = false
): void {
const key = `${target}.${property}`;
const stats = globalRegistry.usage.get(key);
if (stats) {
stats.callCount++;
stats.lastUsed = new Date();
stats.averageExecutionTime =
(stats.averageExecutionTime * (stats.callCount - 1) + executionTime) / stats.callCount;
if (hadError) {
stats.errorCount++;
}
}
}
// 📊 Generate augmentation report
export function generateAugmentationReport(): {
totalAugmentations: number;
activeAugmentations: string[];
conflictSummary: {
warningCount: number;
errorCount: number;
conflicts: ConflictInfo[];
};
usageSummary: {
mostUsed: Array<{ property: string; usage: UsageStats }>;
leastUsed: Array<{ property: string; usage: UsageStats }>;
errorProne: Array<{ property: string; errorRate: number }>;
};
recommendations: string[];
} {
console.log('📊 Generating global augmentation report...');
const totalAugmentations = globalRegistry.augmentations.size;
const activeAugmentations = Array.from(globalRegistry.augmentations.keys());
// 🚨 Conflict summary
const warningCount = globalRegistry.conflicts.filter(c => c.severity === 'warning').length;
const errorCount = globalRegistry.conflicts.filter(c => c.severity === 'error').length;
// 📈 Usage analysis
const usageEntries = Array.from(globalRegistry.usage.entries());
const sortedByUsage = usageEntries.sort(([,a], [,b]) => b.callCount - a.callCount);
const mostUsed = sortedByUsage.slice(0, 5).map(([property, usage]) => ({ property, usage }));
const leastUsed = sortedByUsage.slice(-5).reverse().map(([property, usage]) => ({ property, usage }));
const errorProne = usageEntries
.map(([property, usage]) => ({
property,
errorRate: usage.callCount > 0 ? usage.errorCount / usage.callCount : 0
}))
.filter(item => item.errorRate > 0)
.sort((a, b) => b.errorRate - a.errorRate)
.slice(0, 5);
// 💡 Generate recommendations
const recommendations: string[] = [];
if (errorCount > 0) {
recommendations.push('Resolve critical conflicts to prevent runtime errors');
}
if (errorProne.length > 0) {
recommendations.push('Review error-prone augmentations for stability improvements');
}
if (leastUsed.some(item => item.usage.callCount === 0)) {
recommendations.push('Consider removing unused augmentations to reduce overhead');
}
return {
totalAugmentations,
activeAugmentations,
conflictSummary: {
warningCount,
errorCount,
conflicts: globalRegistry.conflicts
},
usageSummary: {
mostUsed,
leastUsed,
errorProne
},
recommendations
};
}
// 🔧 Validate global augmentation safety
export function validateAugmentationSafety(target: string): {
isSafe: boolean;
issues: SafetyIssue[];
recommendations: string[];
} {
console.log(`🔧 Validating augmentation safety for: ${target}`);
const issues: SafetyIssue[] = [];
const recommendations: string[] = [];
// 🔍 Check for prototype pollution risks
if (target.includes('prototype')) {
const prototypePollutionRisk = checkPrototypePollutionRisk(target);
if (prototypePollutionRisk.isRisky) {
issues.push({
type: 'prototype_pollution',
severity: 'high',
description: 'Potential prototype pollution vulnerability',
affectedProperty: prototypePollutionRisk.property
});
recommendations.push('Use more specific type declarations to avoid prototype pollution');
}
}
// 🔍 Check for naming conflicts
const namingConflicts = checkNamingConflicts(target);
if (namingConflicts.length > 0) {
issues.push(...namingConflicts);
recommendations.push('Use unique property names to avoid conflicts with existing APIs');
}
// 🔍 Check for performance impacts
const performanceImpact = checkPerformanceImpact(target);
if (performanceImpact.hasImpact) {
issues.push({
type: 'performance',
severity: 'medium',
description: 'Potential performance impact detected',
affectedProperty: performanceImpact.property
});
recommendations.push('Consider lazy initialization or caching for performance-sensitive operations');
}
const isSafe = issues.filter(issue => issue.severity === 'high').length === 0;
return {
isSafe,
issues,
recommendations
};
}
export interface SafetyIssue {
type: 'prototype_pollution' | 'naming_conflict' | 'performance' | 'security';
severity: 'low' | 'medium' | 'high';
description: string;
affectedProperty?: string;
}
// 🔍 Check for prototype pollution risks
function checkPrototypePollutionRisk(target: string): {
isRisky: boolean;
property?: string;
} {
// Simplified check - in reality, this would be more sophisticated
const riskyPatterns = ['__proto__', 'constructor', 'valueOf', 'toString'];
for (const pattern of riskyPatterns) {
if (target.includes(pattern)) {
return { isRisky: true, property: pattern };
}
}
return { isRisky: false };
}
// 🔍 Check for naming conflicts
function checkNamingConflicts(target: string): SafetyIssue[] {
const issues: SafetyIssue[] = [];
// Check against known global properties
const knownGlobals = [
'window', 'document', 'console', 'localStorage', 'sessionStorage',
'setTimeout', 'setInterval', 'fetch', 'XMLHttpRequest'
];
knownGlobals.forEach(global => {
if (target.includes(global)) {
issues.push({
type: 'naming_conflict',
severity: 'medium',
description: `Potential conflict with global object: ${global}`,
affectedProperty: global
});
}
});
return issues;
}
// 🔍 Check for performance impacts
function checkPerformanceImpact(target: string): {
hasImpact: boolean;
property?: string;
} {
// Check for potentially expensive operations
const expensivePatterns = ['prototype', 'Array', 'Object', 'String'];
for (const pattern of expensivePatterns) {
if (target.includes(pattern)) {
return { hasImpact: true, property: pattern };
}
}
return { hasImpact: false };
}
// 🛡️ Security scanner for global augmentations
export class GlobalSecurityScanner {
static scanAugmentation(target: string, properties: string[]): SecurityScanResult {
console.log(`🛡️ Scanning augmentation security: ${target}`);
const vulnerabilities: SecurityVulnerability[] = [];
const warnings: SecurityWarning[] = [];
properties.forEach(property => {
// 🔍 Check for injection vulnerabilities
if (this.isInjectionVulnerable(property)) {
vulnerabilities.push({
type: 'injection',
property,
description: 'Property may be vulnerable to injection attacks',
recommendation: 'Implement proper input validation and sanitization'
});
}
// 🔍 Check for privilege escalation
if (this.hasPrivilegeEscalationRisk(property)) {
vulnerabilities.push({
type: 'privilege_escalation',
property,
description: 'Property may allow privilege escalation',
recommendation: 'Implement proper access controls and validation'
});
}
// 🔍 Check for data exposure
if (this.hasDataExposureRisk(property)) {
warnings.push({
type: 'data_exposure',
property,
description: 'Property may expose sensitive data',
recommendation: 'Ensure sensitive data is properly protected'
});
}
});
const riskLevel = this.calculateRiskLevel(vulnerabilities, warnings);
return {
target,
riskLevel,
vulnerabilities,
warnings,
isSecure: vulnerabilities.length === 0,
recommendations: this.generateSecurityRecommendations(vulnerabilities, warnings)
};
}
private static isInjectionVulnerable(property: string): boolean {
const vulnerablePatterns = ['eval', 'innerHTML', 'outerHTML', 'insertAdjacentHTML'];
return vulnerablePatterns.some(pattern => property.toLowerCase().includes(pattern));
}
private static hasPrivilegeEscalationRisk(property: string): boolean {
const riskyPatterns = ['admin', 'root', 'sudo', 'exec', 'system'];
return riskyPatterns.some(pattern => property.toLowerCase().includes(pattern));
}
private static hasDataExposureRisk(property: string): boolean {
const sensitivePatterns = ['password', 'token', 'secret', 'private', 'confidential'];
return sensitivePatterns.some(pattern => property.toLowerCase().includes(pattern));
}
private static calculateRiskLevel(
vulnerabilities: SecurityVulnerability[],
warnings: SecurityWarning[]
): 'low' | 'medium' | 'high' | 'critical' {
if (vulnerabilities.length >= 3) return 'critical';
if (vulnerabilities.length >= 1) return 'high';
if (warnings.length >= 3) return 'medium';
return 'low';
}
private static generateSecurityRecommendations(
vulnerabilities: SecurityVulnerability[],
warnings: SecurityWarning[]
): string[] {
const recommendations: string[] = [];
if (vulnerabilities.length > 0) {
recommendations.push('Address all security vulnerabilities before deployment');
recommendations.push('Implement comprehensive input validation');
recommendations.push('Use security linting tools in your build process');
}
if (warnings.length > 0) {
recommendations.push('Review security warnings and implement mitigations');
recommendations.push('Consider security audit for sensitive operations');
}
recommendations.push('Follow principle of least privilege for global augmentations');
recommendations.push('Regularly update security scanning and review processes');
return recommendations;
}
}
export interface SecurityScanResult {
target: string;
riskLevel: 'low' | 'medium' | 'high' | 'critical';
vulnerabilities: SecurityVulnerability[];
warnings: SecurityWarning[];
isSecure: boolean;
recommendations: string[];
}
export interface SecurityVulnerability {
type: 'injection' | 'privilege_escalation' | 'data_breach';
property: string;
description: string;
recommendation: string;
}
export interface SecurityWarning {
type: 'data_exposure' | 'weak_validation' | 'insecure_default';
property: string;
description: string;
recommendation: string;
}
}
// 🎮 Usage examples and demonstrations
const globalAugmentationDemo = (): void => {
// 📝 Register example augmentations
GlobalAugmentationManager.registerAugmentation({
target: 'Array.prototype',
properties: [
{
name: 'findLast',
type: 'method',
signature: 'findLast<T>(predicate: (value: T, index: number, array: T[]) => boolean): T | undefined',
description: 'Finds the last element that matches the predicate',
examples: ['[1,2,3,4].findLast(x => x % 2 === 0) // returns 4']
},
{
name: 'chunk',
type: 'method',
signature: 'chunk<T>(size: number): T[][]',
description: 'Splits array into chunks of specified size',
examples: ['[1,2,3,4,5].chunk(2) // returns [[1,2], [3,4], [5]]']
}
],
source: 'ArrayExtensions',
version: '1.0.0',
description: 'Utility methods for arrays',
dependencies: []
});
GlobalAugmentationManager.registerAugmentation({
target: 'String.prototype',
properties: [
{
name: 'capitalize',
type: 'method',
signature: 'capitalize(): string',
description: 'Capitalizes the first letter and lowercases the rest',
examples: ['"hello world".capitalize() // returns "Hello world"']
},
{
name: 'isEmail',
type: 'method',
signature: 'isEmail(): boolean',
description: 'Validates if string is a valid email format',
examples: ['"[email protected]".isEmail() // returns true']
}
],
source: 'StringExtensions',
version: '1.0.0',
description: 'Utility methods for strings',
dependencies: []
});
// 📊 Track some usage
GlobalAugmentationManager.trackUsage('Array.prototype', 'findLast', 2.5);
GlobalAugmentationManager.trackUsage('Array.prototype', 'chunk', 1.8);
GlobalAugmentationManager.trackUsage('String.prototype', 'capitalize', 0.9);
GlobalAugmentationManager.trackUsage('String.prototype', 'isEmail', 1.2, true); // With error
// 📋 Generate comprehensive report
const augmentationReport = GlobalAugmentationManager.generateAugmentationReport();
console.log('📋 Global Augmentation Report:', augmentationReport);
// 🔧 Validate safety
const arraySafety = GlobalAugmentationManager.validateAugmentationSafety('Array.prototype');
const stringSafety = GlobalAugmentationManager.validateAugmentationSafety('String.prototype');
console.log('🔧 Safety Validation:', { arraySafety, stringSafety });
// 🛡️ Security scan
const scanner = GlobalAugmentationManager.GlobalSecurityScanner;
const securityScan = scanner.scanAugmentation('String.prototype', ['capitalize', 'isEmail', 'innerHTML']);
console.log('🛡️ Security Scan Results:', securityScan);
console.log('✅ Global augmentation demo completed successfully!');
};
// 🎯 Execute demonstration
globalAugmentationDemo();
💡 Common Global Augmentation Patterns
Let’s explore the most effective and safe patterns for global augmentation:
// 🌟 Pattern 1: Safe Built-in Extensions
// Extend built-in objects safely without conflicts
declare global {
interface Array<T> {
// Utility methods that don't conflict with existing or future standards
safeChunk(size: number): T[][];
safeFindLast(predicate: (value: T) => boolean): T | undefined;
safeUnique(keyFn?: (item: T) => any): T[];
}
interface Object {
// Safe object utilities
safeClone<T>(this: T): T;
safeIsEmpty(this: object): boolean;
safeKeys<T>(this: T): Array<keyof T>;
}
interface Map<K, V> {
// Enhanced map operations
safeGetOrSet(key: K, defaultValue: V | (() => V)): V;
safeUpdateAndGet(key: K, updater: (current: V | undefined) => V): V;
safeFilterEntries(predicate: (key: K, value: V) => boolean): Map<K, V>;
}
interface Set<T> {
// Enhanced set operations
safeUnion(other: Set<T>): Set<T>;
safeIntersection(other: Set<T>): Set<T>;
safeDifference(other: Set<T>): Set<T>;
}
}
// Implementation of safe extensions
Array.prototype.safeChunk = function<T>(this: T[], size: number): T[][] {
if (size <= 0) throw new Error('Chunk size must be positive');
const result: T[][] = [];
for (let i = 0; i < this.length; i += size) {
result.push(this.slice(i, i + size));
}
return result;
};
Array.prototype.safeFindLast = function<T>(
this: T[],
predicate: (value: T) => boolean
): T | undefined {
for (let i = this.length - 1; i >= 0; i--) {
if (predicate(this[i])) return this[i];
}
return undefined;
};
Array.prototype.safeUnique = function<T>(
this: T[],
keyFn?: (item: T) => any
): T[] {
if (!keyFn) return [...new Set(this)];
const seen = new Set();
return this.filter(item => {
const key = keyFn(item);
if (seen.has(key)) return false;
seen.add(key);
return true;
});
};
// 🌟 Pattern 2: Application-Specific Global Utilities
// Create application-wide utilities in a dedicated namespace
declare global {
namespace AppUtils {
// Logging utilities
interface Logger {
debug(message: string, context?: any): void;
info(message: string, context?: any): void;
warn(message: string, context?: any): void;
error(message: string, context?: any): void;
group(name: string): void;
groupEnd(): void;
}
// HTTP utilities
interface Http {
get<T>(url: string, options?: RequestInit): Promise<T>;
post<T>(url: string, data?: any, options?: RequestInit): Promise<T>;
put<T>(url: string, data?: any, options?: RequestInit): Promise<T>;
delete<T>(url: string, options?: RequestInit): Promise<T>;
}
// Storage utilities
interface Storage {
local: {
get<T>(key: string): T | null;
set<T>(key: string, value: T): void;
remove(key: string): void;
clear(): void;
};
session: {
get<T>(key: string): T | null;
set<T>(key: string, value: T): void;
remove(key: string): void;
clear(): void;
};
}
// Validation utilities
interface Validator {
email(value: string): boolean;
url(value: string): boolean;
phoneNumber(value: string): boolean;
creditCard(value: string): boolean;
strongPassword(value: string): boolean;
custom<T>(value: T, rules: ValidationRule<T>[]): ValidationResult;
}
interface ValidationRule<T> {
name: string;
validator: (value: T) => boolean;
message: string;
}
interface ValidationResult {
isValid: boolean;
errors: string[];
}
// Event utilities
interface Events {
on<T>(event: string, handler: (data: T) => void): () => void;
off(event: string, handler?: Function): void;
emit<T>(event: string, data?: T): void;
once<T>(event: string, handler: (data: T) => void): void;
}
// Performance utilities
interface Performance {
mark(name: string): void;
measure(name: string, startMark?: string, endMark?: string): number;
time<T>(name: string, fn: () => T): T;
timeAsync<T>(name: string, fn: () => Promise<T>): Promise<T>;
}
// Formatting utilities
interface Format {
currency(amount: number, currency?: string): string;
number(value: number, decimals?: number): string;
bytes(bytes: number): string;
percentage(value: number, decimals?: number): string;
date(date: Date, format?: string): string;
relativeTime(date: Date): string;
}
}
// Global utility instance
var utils: {
logger: AppUtils.Logger;
http: AppUtils.Http;
storage: AppUtils.Storage;
validator: AppUtils.Validator;
events: AppUtils.Events;
performance: AppUtils.Performance;
format: AppUtils.Format;
};
}
// Implementation of application utilities
if (typeof window !== 'undefined') {
window.utils = {
logger: {
debug: (message: string, context?: any) => {
if (process.env.NODE_ENV === 'development') {
console.debug(`[DEBUG] ${message}`, context || '');
}
},
info: (message: string, context?: any) => {
console.info(`[INFO] ${message}`, context || '');
},
warn: (message: string, context?: any) => {
console.warn(`[WARN] ${message}`, context || '');
},
error: (message: string, context?: any) => {
console.error(`[ERROR] ${message}`, context || '');
},
group: (name: string) => console.group(name),
groupEnd: () => console.groupEnd()
},
http: {
async get<T>(url: string, options?: RequestInit): Promise<T> {
const response = await fetch(url, { ...options, method: 'GET' });
if (!response.ok) throw new Error(`HTTP ${response.status}: ${response.statusText}`);
return response.json();
},
async post<T>(url: string, data?: any, options?: RequestInit): Promise<T> {
const response = await fetch(url, {
...options,
method: 'POST',
headers: { 'Content-Type': 'application/json', ...options?.headers },
body: data ? JSON.stringify(data) : undefined
});
if (!response.ok) throw new Error(`HTTP ${response.status}: ${response.statusText}`);
return response.json();
},
async put<T>(url: string, data?: any, options?: RequestInit): Promise<T> {
const response = await fetch(url, {
...options,
method: 'PUT',
headers: { 'Content-Type': 'application/json', ...options?.headers },
body: data ? JSON.stringify(data) : undefined
});
if (!response.ok) throw new Error(`HTTP ${response.status}: ${response.statusText}`);
return response.json();
},
async delete<T>(url: string, options?: RequestInit): Promise<T> {
const response = await fetch(url, { ...options, method: 'DELETE' });
if (!response.ok) throw new Error(`HTTP ${response.status}: ${response.statusText}`);
return response.json();
}
},
storage: {
local: {
get<T>(key: string): T | null {
try {
const item = localStorage.getItem(key);
return item ? JSON.parse(item) : null;
} catch {
return null;
}
},
set<T>(key: string, value: T): void {
try {
localStorage.setItem(key, JSON.stringify(value));
} catch (error) {
console.error('Failed to save to localStorage:', error);
}
},
remove(key: string): void {
localStorage.removeItem(key);
},
clear(): void {
localStorage.clear();
}
},
session: {
get<T>(key: string): T | null {
try {
const item = sessionStorage.getItem(key);
return item ? JSON.parse(item) : null;
} catch {
return null;
}
},
set<T>(key: string, value: T): void {
try {
sessionStorage.setItem(key, JSON.stringify(value));
} catch (error) {
console.error('Failed to save to sessionStorage:', error);
}
},
remove(key: string): void {
sessionStorage.removeItem(key);
},
clear(): void {
sessionStorage.clear();
}
}
},
validator: {
email: (value: string) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value),
url: (value: string) => {
try {
new URL(value);
return true;
} catch {
return false;
}
},
phoneNumber: (value: string) => /^\+?[\d\s\-\(\)]{10,}$/.test(value),
creditCard: (value: string) => /^\d{13,19}$/.test(value.replace(/\s/g, '')),
strongPassword: (value: string) => {
return value.length >= 8 &&
/[A-Z]/.test(value) &&
/[a-z]/.test(value) &&
/\d/.test(value) &&
/[!@#$%^&*(),.?":{}|<>]/.test(value);
},
custom<T>(value: T, rules: AppUtils.ValidationRule<T>[]): AppUtils.ValidationResult {
const errors: string[] = [];
rules.forEach(rule => {
if (!rule.validator(value)) {
errors.push(rule.message);
}
});
return {
isValid: errors.length === 0,
errors
};
}
},
events: (() => {
const eventHandlers = new Map<string, Function[]>();
return {
on<T>(event: string, handler: (data: T) => void): () => void {
if (!eventHandlers.has(event)) {
eventHandlers.set(event, []);
}
eventHandlers.get(event)!.push(handler);
return () => this.off(event, handler);
},
off(event: string, handler?: Function): void {
if (!eventHandlers.has(event)) return;
if (handler) {
const handlers = eventHandlers.get(event)!;
const index = handlers.indexOf(handler);
if (index > -1) handlers.splice(index, 1);
} else {
eventHandlers.delete(event);
}
},
emit<T>(event: string, data?: T): void {
const handlers = eventHandlers.get(event);
if (handlers) {
handlers.forEach(handler => {
try {
handler(data);
} catch (error) {
console.error(`Error in event handler for ${event}:`, error);
}
});
}
},
once<T>(event: string, handler: (data: T) => void): void {
const onceHandler = (data: T) => {
handler(data);
this.off(event, onceHandler);
};
this.on(event, onceHandler);
}
};
})(),
performance: {
mark(name: string): void {
if (performance && performance.mark) {
performance.mark(name);
}
},
measure(name: string, startMark?: string, endMark?: string): number {
if (performance && performance.measure && performance.getEntriesByName) {
performance.measure(name, startMark, endMark);
const measures = performance.getEntriesByName(name);
return measures.length > 0 ? measures[measures.length - 1].duration : 0;
}
return 0;
},
time<T>(name: string, fn: () => T): T {
const start = Date.now();
const result = fn();
const duration = Date.now() - start;
console.log(`${name} took ${duration}ms`);
return result;
},
async timeAsync<T>(name: string, fn: () => Promise<T>): Promise<T> {
const start = Date.now();
const result = await fn();
const duration = Date.now() - start;
console.log(`${name} took ${duration}ms`);
return result;
}
},
format: {
currency(amount: number, currency: string = 'USD'): string {
return new Intl.NumberFormat('en-US', {
style: 'currency',
currency
}).format(amount);
},
number(value: number, decimals: number = 0): string {
return new Intl.NumberFormat('en-US', {
minimumFractionDigits: decimals,
maximumFractionDigits: decimals
}).format(value);
},
bytes(bytes: number): string {
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
if (bytes === 0) return '0 Bytes';
const i = Math.floor(Math.log(bytes) / Math.log(1024));
return `${(bytes / Math.pow(1024, i)).toFixed(2)} ${sizes[i]}`;
},
percentage(value: number, decimals: number = 1): string {
return `${(value * 100).toFixed(decimals)}%`;
},
date(date: Date, format: string = 'yyyy-MM-dd'): string {
const map: Record<string, string> = {
'yyyy': date.getFullYear().toString(),
'MM': (date.getMonth() + 1).toString().padStart(2, '0'),
'dd': date.getDate().toString().padStart(2, '0'),
'HH': date.getHours().toString().padStart(2, '0'),
'mm': date.getMinutes().toString().padStart(2, '0'),
'ss': date.getSeconds().toString().padStart(2, '0')
};
return format.replace(/yyyy|MM|dd|HH|mm|ss/g, match => map[match]);
},
relativeTime(date: Date): string {
const now = new Date();
const diffMs = now.getTime() - date.getTime();
const diffMins = Math.floor(diffMs / (1000 * 60));
const diffHours = Math.floor(diffMins / 60);
const diffDays = Math.floor(diffHours / 24);
if (diffMins < 1) return 'just now';
if (diffMins < 60) return `${diffMins} minute${diffMins !== 1 ? 's' : ''} ago`;
if (diffHours < 24) return `${diffHours} hour${diffHours !== 1 ? 's' : ''} ago`;
return `${diffDays} day${diffDays !== 1 ? 's' : ''} ago`;
}
}
};
}
// 🌟 Pattern 3: Library Enhancement
// Safely enhance third-party library types
declare global {
// Enhance React types (if using React)
namespace JSX {
interface IntrinsicElements {
'custom-element': React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement> & {
customProp?: string;
};
}
}
// Enhance Express types (if using Express)
namespace Express {
interface Request {
user?: {
id: string;
email: string;
roles: string[];
};
startTime?: number;
traceId?: string;
}
interface Response {
success<T>(data: T): Response;
error(message: string, code?: number): Response;
}
}
// Enhance Node.js types
namespace NodeJS {
interface ProcessEnv {
readonly NODE_ENV: 'development' | 'staging' | 'production' | 'test';
readonly PORT?: string;
readonly DATABASE_URL?: string;
readonly JWT_SECRET?: string;
readonly API_KEY?: string;
}
interface Global {
__DEV__: boolean;
__TEST__: boolean;
__PROD__: boolean;
}
}
}
// Demonstration of global utilities usage
const demonstrateGlobalUtilities = async (): Promise<void> => {
console.log('🌟 Demonstrating Global Utilities');
// Array extensions
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const chunks = numbers.safeChunk(3);
const lastEven = numbers.safeFindLast(n => n % 2 === 0);
const unique = [1, 2, 2, 3, 3, 4].safeUnique();
console.log('📊 Array utilities:', { chunks, lastEven, unique });
// Application utilities
utils.logger.info('Application started', { version: '1.0.0' });
// Storage utilities
utils.storage.local.set('user-preferences', { theme: 'dark', language: 'en' });
const preferences = utils.storage.local.get<{ theme: string; language: string }>('user-preferences');
console.log('💾 Storage utilities:', preferences);
// Validation utilities
const emailValid = utils.validator.email('[email protected]');
const passwordValid = utils.validator.strongPassword('MyStr0ng!Pass');
const customValidation = utils.validator.custom('[email protected]', [
{
name: 'email',
validator: (value: string) => utils.validator.email(value),
message: 'Must be a valid email'
},
{
name: 'domain',
validator: (value: string) => value.endsWith('@example.com'),
message: 'Must be from example.com domain'
}
]);
console.log('✅ Validation utilities:', { emailValid, passwordValid, customValidation });
// Event utilities
const unsubscribe = utils.events.on<{ message: string }>('user-action', (data) => {
console.log('📡 Event received:', data);
});
utils.events.emit('user-action', { message: 'User clicked button' });
unsubscribe();
// Performance utilities
const result = utils.performance.time('calculation', () => {
return Array.from({ length: 1000 }, (_, i) => i * i).reduce((sum, val) => sum + val, 0);
});
console.log('⚡ Performance utilities:', result);
// Format utilities
const formatted = {
currency: utils.format.currency(1234.56),
bytes: utils.format.bytes(1024 * 1024 * 2.5),
percentage: utils.format.percentage(0.756),
date: utils.format.date(new Date(), 'yyyy-MM-dd HH:mm'),
relativeTime: utils.format.relativeTime(new Date(Date.now() - 2 * 60 * 60 * 1000))
};
console.log('🎨 Format utilities:', formatted);
console.log('✅ Global utilities demonstration completed!');
};
// Execute the demonstration
demonstrateGlobalUtilities();
🎉 Conclusion
Congratulations! You’ve mastered the power of global augmentation! 🌍
🎯 What You’ve Learned
- 🌍 Global Augmentation Syntax: Using declare global to extend built-in and global types
- 🛡️ Safety Practices: Implementing secure and conflict-free global enhancements
- 🔧 Advanced Patterns: Sophisticated strategies for extending global scope responsibly
- 📊 Management Systems: Tools for tracking, analyzing, and optimizing global augmentations
- 🚀 Practical Applications: Real-world examples of powerful global utilities
🚀 Key Benefits
- ⚡ Enhanced Built-ins: Add powerful functionality to JavaScript’s built-in objects
- 🌐 Global Utilities: Create application-wide tools available everywhere
- 🎯 Type Safety: Maintain full TypeScript type checking for global enhancements
- 🔧 Developer Experience: Improve productivity with convenient global functions
- 📚 Library Enhancement: Safely extend third-party library types and interfaces
🔥 Best Practices Recap
- 🛡️ Safety First: Always validate augmentations for security and conflicts
- 📝 Use Prefixes: Prefix custom methods to avoid naming conflicts
- 🔧 Test Thoroughly: Comprehensive testing for global modifications
- 📊 Monitor Usage: Track and analyze global augmentation usage patterns
- 🌱 Evolve Carefully: Plan for long-term maintenance and updates
You’re now equipped to safely and effectively enhance the global scope with powerful, type-safe augmentations that can transform your development experience! Whether you’re creating utility functions, enhancing built-in objects, or extending library types, global augmentation provides the tools you need. 🌟
Happy coding, and may your global enhancements always be safe and powerful! 🌍✨