【TypeScript】仕様変更に強いFizzBuzz


ネタ元:「fizzbuzzについて思うこと」
Kotlin版:【Kotlin】仕様変更に強い FizzBuzz

FizzBuzz の、割る数、出力する文字列、変換規則の数や順番が変わっても
最小限のコード変更で済むようにする。

/**
 * FizzBuzz の変換規則を表す型。
 * 入力された数値を割る数と、
 * 割り切れたときに出力に追加する文字列との組の列。
 */
type FizzBuzzMap = Iterable<
    Readonly<[number, string]>
>;

/**
 * FizzBuzz で入力された1つの数値を
 * 変換規則に従って文字列に変換する
 * 関数を返す。
 * 
 * @param map 変換規則。
 * @returns 数値を文字列に変換する関数。
 */
function fizzBuzzFunctionCreator(
    map: FizzBuzzMap
): (num: number) => string {
    return (num: number) => {
        const strs: string[] = [];
        for (const entry of map) {
            if (num % entry[0] == 0) {
                strs.push(entry[1]);
            }
        }
        return strs.length > 0 ? strs.join("") : `${num}`;
    };
}

使用例

普通の FizzBuzz

/** 変換規則の定義。 */
const FIZZ_BUZZ_MAP: FizzBuzzMap = [
    [3, "Fizz"],
    [5, "Buzz"],
];

/** 数値を変換規則に従って変換する関数。 */
const fizzBuzzFunction: (num: number) => string
    = fizzBuzzFunctionCreator(FIZZ_BUZZ_MAP);

for (let i = 1; i <= 15; ++i) {
    console.log(
        fizzBuzzFunction(i)
    );
}

出力

1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
11
Fizz
13
14
FizzBuzz

Fizz と Buzz の優先順を入れ替える

const FIZZ_BUZZ_MAP: FizzBuzzMap = [
    [5, "Buzz"],
    [3, "Fizz"],
];

// 他は同じなので省略

出力

1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
11
Fizz
13
14
BuzzFizz

こんなことも

const FIZZ_BUZZ_MAP: FizzBuzzMap = [
    [1, "<"],
    [3, "Fizz"],
    [5, "Buzz"],
    [1, ">"],
];

// 他は同じなので省略

出力

<>
<Fizz>
<>
<Buzz>
<Fizz>
<>
<Fizz>
<Buzz>
<>
<Fizz>
<>
<FizzBuzz>

/以上