Profile Icon

『プログラミングTypeScript』 第四章 - is メソッドの実装

プログラミングTypeScript』の第四章の練習問題に次のようなものがある。

  1. 型安全なアサーション関数、isを実装してください。型で概略を記述することから始めます。これは、完成したら、次のように使えるものです。
// stringとstringを比較します
is('string', 'otherstring') // false

// booleanとbooleanを比較します
is(true, false) // false

// numberとnumberを比較します
is(42, 42) // true

// 異なる型同士を比較すると、コンパイル時エラーになります
is(10, 'foo') // エラー TS2345: 型 '"foo"' の引数を型 'number' の
              // パラメーターに割り当てることはできません。

よしよし、そんなに難しくはなさそうだ。この章の後半で出てきたジェネリック型を使えばできるのだろう。こうかな?

function is<T>(first: T, second: T) {
  return first === second;
}

動いているようだな。おっ、この問題には続きがあるようだ...

// [難問]任意の数の引数を渡せるようにします
is([1], [1, 2], [1, 2, 3]); // false

ふむふむ、何個の引数が渡されるかわからないのであれば、レストパラメーターを使えばいけるだろう。俺は詳しいんだ。

function is<T>(first: T, ...rest: T[]) {
  return rest.every(_ => _ === first);
}

うんうん、これも期待通りに動くな。ここで本の解答を眺めると...あれ、ちょっと僕の書いたものとは違う。

function is<T>(first: T, ...rest: [T, ...T[]]): boolean {
  return rest.every(_ => _ === first)
}

...あっ、なるほど。もとの ...rest: T[] だと is('foo') のような入力も許されてしまうのか...これは失態だ。rest が少なくともひとつの要素をもつことを保証するためには ...rest: [T, ...T[]] のように書く必要がある

こういうケースには自分で気づけないといけないな。