/**
 * TypeScript Utility Types and Helper Functions
 *
 * Provides comprehensive TypeScript utilities for:
 * - Advanced type manipulation
 * - Functional programming patterns
 * - Immutable data structures
 * - Runtime type checking
 */
/**
 * Runtime type checking utilities
 */
export class TypeGuards {
    /**
     * Check if value is a string
     */
    static isString(value) {
        return typeof value === 'string';
    }
    /**
     * Check if value is a number
     */
    static isNumber(value) {
        return typeof value === 'number' && !isNaN(value);
    }
    /**
     * Check if value is a boolean
     */
    static isBoolean(value) {
        return typeof value === 'boolean';
    }
    /**
     * Check if value is an object (not null, not array)
     */
    static isObject(value) {
        return typeof value === 'object' && value !== null && !Array.isArray(value);
    }
    /**
     * Check if value is an array
     */
    static isArray(value) {
        return Array.isArray(value);
    }
    /**
     * Check if value is a function
     */
    static isFunction(value) {
        return typeof value === 'function';
    }
    /**
     * Check if value is null or undefined
     */
    static isNil(value) {
        return value === null || value === undefined;
    }
    /**
     * Check if value has a specific property
     */
    static hasProperty(value, property) {
        return TypeGuards.isObject(value) && property in value;
    }
}
/**
 * Functional programming utilities
 */
export class Functional {
    /**
     * Compose multiple functions
     */
    static compose(...fns) {
        return (x) => fns.reduceRight((acc, fn) => fn(acc), x);
    }
    /**
     * Pipe value through multiple functions
     */
    static pipe(value, ...fns) {
        return fns.reduce((acc, fn) => fn(acc), value);
    }
    /**
     * Memoize function with cache
     */
    static memoize(fn, cacheKey) {
        const cache = new Map();
        return ((...args) => {
            const key = cacheKey ? cacheKey(...args) : JSON.stringify(args);
            if (cache.has(key)) {
                return cache.get(key);
            }
            const result = fn(...args);
            cache.set(key, result);
            return result;
        });
    }
    /**
     * Debounce function execution
     */
    static debounce(fn, delay) {
        let timeoutId;
        return (...args) => {
            clearTimeout(timeoutId);
            timeoutId = setTimeout(() => fn(...args), delay);
        };
    }
    /**
     * Throttle function execution
     */
    static throttle(fn, delay) {
        let lastCall = 0;
        return (...args) => {
            const now = Date.now();
            if (now - lastCall >= delay) {
                lastCall = now;
                fn(...args);
            }
        };
    }
}
/**
 * Immutable data utilities
 */
export class Immutable {
    /**
     * Deep freeze object
     */
    static deepFreeze(obj) {
        if (typeof obj !== 'object' || obj === null) {
            return obj;
        }
        Object.freeze(obj);
        Object.getOwnPropertyNames(obj).forEach(prop => {
            const value = obj[prop];
            if (value &&
                typeof value === 'object' &&
                !Object.isFrozen(value)) {
                Immutable.deepFreeze(value);
            }
        });
        return obj;
    }
    /**
     * Create immutable copy with updates
     */
    static update(obj, updates) {
        return { ...obj, ...updates };
    }
    /**
     * Create immutable copy with nested updates
     */
    static updateIn(obj, path, value) {
        if (path.length === 0) {
            return obj;
        }
        const [first, ...rest] = path;
        if (rest.length === 0) {
            return { ...obj, [first]: value };
        }
        const current = obj[first];
        if (!TypeGuards.isObject(current)) {
            throw new Error(`Cannot update non-object at path: ${first}`);
        }
        return {
            ...obj,
            [first]: Immutable.updateIn(current, rest, value)
        };
    }
}
/**
 * Type-safe event emitter
 */
export class TypedEventEmitter {
    listeners = {};
    /**
     * Add event listener
     */
    on(event, listener) {
        if (!this.listeners[event]) {
            this.listeners[event] = [];
        }
        this.listeners[event].push(listener);
    }
    /**
     * Remove event listener
     */
    off(event, listener) {
        if (!this.listeners[event]) {
            return;
        }
        const index = this.listeners[event].indexOf(listener);
        if (index !== -1) {
            this.listeners[event].splice(index, 1);
        }
    }
    /**
     * Emit event
     */
    emit(event, ...args) {
        if (!this.listeners[event]) {
            return;
        }
        this.listeners[event].forEach(listener => {
            try {
                listener(...args);
            }
            catch (error) {
                console.error(`Error in event listener for ${String(event)}:`, error);
            }
        });
    }
    /**
     * Remove all listeners
     */
    removeAllListeners() {
        this.listeners = {};
    }
}
/**
 * Utility functions for common TypeScript patterns
 */
export class TypeScriptUtils {
    /**
     * Assert value is not null or undefined
     */
    static assertDefined(value, message) {
        if (value === null || value === undefined) {
            throw new Error(message ?? 'Value is null or undefined');
        }
    }
    /**
     * Create type-safe enum from array
     */
    static createStringEnum(values) {
        return values.reduce((acc, value) => {
            acc[value] = value;
            return acc;
        }, {});
    }
    /**
     * Create branded type
     */
    static createBranded(value) {
        return value;
    }
    /**
     * Extract keys from type that match a condition
     */
    static extractKeys(obj, predicate) {
        return Object.keys(obj).filter(key => predicate(key, obj[key]));
    }
    /**
     * Pick properties from object
     */
    static pick(obj, keys) {
        const result = {};
        keys.forEach(key => {
            if (key in obj) {
                result[key] = obj[key];
            }
        });
        return result;
    }
    /**
     * Omit properties from object
     */
    static omit(obj, keys) {
        const result = { ...obj };
        keys.forEach(key => {
            delete result[key];
        });
        return result;
    }
}
//# sourceMappingURL=utilityTypes.js.map