Language Facades

Some random array prototypes I tend to add to most things I do since, so I don’t have to keep reinventing them (handling async in map and foreach is a pain otherwise). I make no claims that these are unique, or that they don’t already exist somewhere on the internets. I can more than likely make claims that there are more efficient ways to do that, but if that was the goal, we would be using Rust instead of Typescript anyhow

Arrays

export {}

declare global {
    interface Array<T> {
        asyncForEach(callback: (x: T) => void, maxConcurrency?: number): Promise<void>
        asyncMap(callback: (x: T) => Promise<U>, maxConcurrency?: number): Promise<U[]>
        distinct(): T[]
    }
}
Array.prototype.asyncForEach = async function<T>(callback: (x:T) => void, maxConcurrency?: number): Promise<void> {
    maxConcurrency = maxConcurrency ?? this.length
    let position = 0
    while (position < this.length) {
        await Promise.all(this.slice(position, position + maxConcurrency).map((x: T) => callback(x)))
        position += maxConcurrency
    }
}
Array.prototype.asyncMap = async function<T, U>(callback: (x:T) => Promise<U>, maxConcurrency?: number): Promise<U[]> {
    maxConcurrency = maxConcurrency ?? this.length
    let position = 0
    const results: U[] = []
    while (position < this.length) {
        const batchResults = await Promise.all(this.slice(position, position + maxConcurrency).map((x: T) => callback(x)))
        results.push(...batchResults)
        position += maxConcurrency
    }
}
Array.prototype.distinct = function<T>(this: T[]): T[] {
    //INFO: if T is primitive, just use Set directly and assume everything is of the same type
    if (typeof this[0] !== 'object') {
        return Array.from(new Set(this))
    }
    //INFO: for non primitives, do a deep compare
    const set = new Set(this.map(x => JSON.stringigy(x)))
    return Array.from(set).map(x => JSON.parse(x))
}