export type Nullable<T> = { [P in keyof T]: T[P] | null }

export type Subset<T> = { [K in keyof T]?: Subset<T[K]> }
export type Dictionary<T> = { [key: string]: T };
export type OneOrMany<T> = T | T[];

export type Index = string | symbol | number;

export interface DOMEvent<TTarget extends EventTarget> extends Event {
    target: TTarget;
}

export function delay(time: number) {
  return new Promise(resolve => setTimeout(resolve, time));
}

export function throttle<TArgs extends any[]>(decorated: (...args: TArgs) => void, time: number = 150) {
    let timeout: number | undefined;
    return function (this: any, ...args: TArgs): void {
        if (typeof timeout !== 'undefined') {
            window.clearTimeout(timeout);
        }

        timeout = window.setTimeout(() => {
            timeout = undefined;
            decorated.call(this, ...args);
        }, time);
    }
}

export function encapsulate<T>(value: OneOrMany<T>): T[] {
    if (value instanceof Array) {
        return value;
    }

    return [ value ];
}

export function one<T>(value: OneOrMany<T>): T {
    if (value instanceof Array) {
        return value[0];
    }

    return value;
}

export function capitalize(value: string): string {
    return value.charAt(0).toUpperCase() + value.slice(1);
}