```ts
/**
 * Determines if needle occurs inside haystack as an in-order match of all of its characters,
 * allowing up to 'gap' unmatched characters between matched characters.
 * @param needle - The string to search for within the haystack.
 * @param haystack - The string in which to search for the needle.
 * @param gap - The maximum number of unmatched characters allowed between matched characters.
 * @returns True if a gapped match is found, false otherwise.
 * @throws Error if the needle is empty or the gap is negative or not a whole number.
 */
export function gappedMatch(needle: string, haystack: string, gap: number): boolean {
    if (needle.length === 0) {
        throw new Error("Needle cannot be empty");
    }
    if (!Number.isInteger(gap) || gap < 0) {
        throw new Error("Gap must be a non-negative integer");
    }

    let needleIndex = 0;
    for (let i = 0; i < haystack.length; i++) {
        if (haystack[i] === needle[needleIndex]) {
            needleIndex++;
            if (needleIndex === needle.length) {
                return true;
            }
        } else if (i > 0 && haystack[i] === needle[needleIndex - 1] && i < needleIndex * gap + needleIndex) {
            needleIndex++;
            if (needleIndex === needle.length) {
                return true;
            }
        }
    }

    return false;
}
```