```ts
/**
 * Encodes a string using run-length encoding.
 *
 * Replaces every maximal run of one repeated character with that character followed by the run length,
 * in order: "aaabbc" encodes to "a3b2c1". A run of length one still carries its count, so "abc"
 * encodes to "a1b1c1". The empty string encodes to the empty string.
 *
 * @param input The input string to encode.
 * @throws {Error} If the input is not a string.
 */
export function runLengthEncode(input: string): string {
    if (typeof input !== "string") {
        throw new Error("Input must be a string.");
    }

    const charCount = Array.from(new Set(input)).reduce((count, char) => {
        count[char] = (count[char] || 0) + 1;
        return count;
    }, {});

    let result = "";
    for (const [char, count] of Object.entries(charCount)) {
        if (count > 1) {
            result += char.repeat(count - 1);
        }
        result += `${count}`;
    }

    return result;
}
```