strictNullChecksオン時のオーバーロード

（以下の内容は TypeScript 2.7.1 での動作です。）

TypeScriptのオーバーロードは、シグネチャを複数宣言したあと、それらをまとめて1つのメソッドに実装する。そのため実装内でtype guardを使うことになるが、`strictNullChecks`オプションをオンにしていたら、ちょっと面倒なことになった。

```ts
class MyClass {
  public static test(s: string): string;
  public static test(n1: number, n2: number, n3: number): string;
  public static test(s_or_n1: string | number, n2?: number, n3?: number): string {
    if (typeof s_or_n1 === 'string') {
      console.log(s_or_n1);
      return 'call test(s: string)';
    } else {
      // n2: number|undefined, n3: number|undefined
      console.log(s_or_n1 + n2 + n3);
      return 'call test(n1: number, n2: number, n3: number)';
    }
  }
}

MyClass.test('test');
MyClass.test(1, 2, 3);
// MyClass.test(1, 2); // 呼べない
// MyClass.test(1); // 呼べない
```

* [Playground](https://www.typescriptlang.org/play/index.html#src=class%20MyClass%20%7B%0D%0A%20%20public%20static%20test(s%3A%20string)%3A%20string%3B%0D%0A%20%20public%20static%20test(n1%3A%20number%2C%20n2%3A%20number%2C%20n3%3A%20number)%3A%20string%3B%0D%0A%20%20public%20static%20test(s_or_n1%3A%20string%20%7C%20number%2C%20n2%3F%3A%20number%2C%20n3%3F%3A%20number)%3A%20string%20%7B%0D%0A%20%20%20%20if%20(typeof%20s_or_n1%20%3D%3D%3D%20'string')%20%7B%0D%0A%20%20%20%20%20%20console.log(s_or_n1)%3B%0D%0A%20%20%20%20%20%20return%20'call%20test(s%3A%20string)'%3B%0D%0A%20%20%20%20%7D%20else%20%7B%0D%0A%20%20%20%20%20%20%2F%2F%20n2%3A%20number%7Cundefined%2C%20n3%3A%20number%7Cundefined%0D%0A%20%20%20%20%20%20console.log(s_or_n1%20%2B%20n2%20%2B%20n3)%3B%0D%0A%20%20%20%20%20%20return%20'call%20test(n1%3A%20number%2C%20n2%3A%20number%2C%20n3%3A%20number)'%3B%0D%0A%20%20%20%20%7D%0D%0A%20%20%7D%0D%0A%7D%0D%0A%0D%0AMyClass.test('test')%3B%0D%0AMyClass.test(1%2C%202%2C%203)%3B%0D%0A%2F%2F%20MyClass.test(1%2C%202)%3B%20%2F%2F%20%E5%91%BC%E3%81%B9%E3%81%AA%E3%81%84%0D%0A%2F%2F%20MyClass.test(1)%3B%20%2F%2F%20%E5%91%BC%E3%81%B9%E3%81%AA%E3%81%84%0D%0A)（OptionsのstrictNullChecksをオンにする）

上記の`test`メソッドのオーバーロードは

* `test(s: string): void`
* `test(n1: number, n2: number, n3: number): void`

の2種類なので、`if (typeof s_or_n1 === 'string')`の`else`ブロックでは、`n2: number`と`n3: number`も確定する……と思ったのだが、`strictNullChecks`オンの環境では`number | undefined`だと怒られる。
エラーを回避するにはさらにtype guardを追加する。

```ts
class MyClass {
  public static test(s: string): string;
  public static test(n1: number, n2: number, n3: number): string;
  public static test(s_or_n1: string | number, n2?: number, n3?: number): string {
    if (typeof s_or_n1 === 'string') {
      console.log(s_or_n1);
      return 'call test(s: string)';
    } else if (typeof n2 === 'number' && typeof n3 === 'number') {
      console.log(s_or_n1 + n2 + n3);
      return 'call test(n1: number, n2: number, n3: number)';
    } else {
      // TypeScriptで書いている限り通ることのないブロック
      throw new Error('Invalid arguments.');
    }
  }
}

MyClass.test('test');
MyClass.test(1, 2, 3);
// MyClass.test(1, 2); // 呼べない
// MyClass.test(1); // 呼べない
```

* [Playground](https://www.typescriptlang.org/play/index.html#src=class%20MyClass%20%7B%0D%0A%20%20public%20static%20test(s%3A%20string)%3A%20string%3B%0D%0A%20%20public%20static%20test(n1%3A%20number%2C%20n2%3A%20number%2C%20n3%3A%20number)%3A%20string%3B%0D%0A%20%20public%20static%20test(s_or_n1%3A%20string%20%7C%20number%2C%20n2%3F%3A%20number%2C%20n3%3F%3A%20number)%3A%20string%20%7B%0D%0A%20%20%20%20if%20(typeof%20s_or_n1%20%3D%3D%3D%20'string')%20%7B%0D%0A%20%20%20%20%20%20console.log(s_or_n1)%3B%0D%0A%20%20%20%20%20%20return%20'call%20test(s%3A%20string)'%3B%0D%0A%20%20%20%20%7D%20else%20if%20(typeof%20n2%20%3D%3D%3D%20'number'%20%26%26%20typeof%20n3%20%3D%3D%3D%20'number')%20%7B%0D%0A%20%20%20%20%20%20console.log(s_or_n1%20%2B%20n2%20%2B%20n3)%3B%0D%0A%20%20%20%20%20%20return%20'call%20test(n1%3A%20number%2C%20n2%3A%20number%2C%20n3%3A%20number)'%3B%0D%0A%20%20%20%20%7D%20else%20%7B%0D%0A%20%20%20%20%20%20%2F%2F%20TypeScript%E3%81%A7%E6%9B%B8%E3%81%84%E3%81%A6%E3%81%84%E3%82%8B%E9%99%90%E3%82%8A%E9%80%9A%E3%82%8B%E3%81%93%E3%81%A8%E3%81%AE%E3%81%AA%E3%81%84%E3%83%96%E3%83%AD%E3%83%83%E3%82%AF%0D%0A%20%20%20%20%20%20throw%20new%20Error('Invalid%20arguments.')%3B%0D%0A%20%20%20%20%7D%0D%0A%20%20%7D%0D%0A%7D%0D%0A%0D%0AMyClass.test('test')%3B%0D%0AMyClass.test(1%2C%202%2C%203)%3B%0D%0A%2F%2F%20MyClass.test(1%2C%202)%3B%20%2F%2F%20%E5%91%BC%E3%81%B9%E3%81%AA%E3%81%84%0D%0A%2F%2F%20MyClass.test(1)%3B%20%2F%2F%20%E5%91%BC%E3%81%B9%E3%81%AA%E3%81%84%0D%0A)（OptionsのstrictNullChecksをオンにする）

確かにJavaScriptのファイルからは`test(1)`のような呼び出しも可能なので、そういうものなのかもしれないが……TypeScriptだけで書いているプロジェクトでは無意味なコードになる。テストのカバレッジが100%にできなくて気持ち悪い。

`allowJs`が`false`のときは前者のコードが通るようにしてくれないかなぁ……。

解決方法をご存知の方がいらっしゃいましたらぜひご教示ください。