TypeScript 3.7 beta の変更点

TypeScript Blogの元ポスト: https://devblogs.microsoft.com/typescript/announcing-typescript-3-7-beta/

個人の判断で説明を省略したり補足したりするので、完全な翻訳はない。元ポストも合わせて参考してください。

## Optional Chaining

TLDR: 大体 Ruby の `a&.property`、Swift / Kotlin の `a?.property` にあたる。

この提案もうES Stage 3 に行ってるので、 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining か ES仕様も参考になる。

### `.` 属性評価

```TypeScript
let foo: null | undefined | { bar: { baz(): number }};

let x = (foo === null || foo === undefined) ?
    undefined :
    foo.bar.baz();

// equivalient to
let x = foo?.bar.baz();
```

### `[]` 属性評価

```TypeScript
function tryGetFirstElement<T>(arr?: T[]) {
    return arr?.[0];

// equivalent to
    return (arr === null || arr === undefined) ?
        undefined :
        arr[0];
}
```

### `()` 関数呼び出し

```ts
function tryCall(foo?: () => void)) {
    foo?.();

// equivalent to

    if (foo !== null && foo !== undefined) {
        foo();
    }
}
```

### 注意点

short circuit評価は *そのoptional chain式の内部だけに* 存在する、式全体までshort circuitになるわけではない。

例:

```ts
let foo: null | { val: number;}
let cez: () => number;

let bar = foo?.val / cez();
// cez() はfooの値と関係なく実行されて、number型になる。
// またfoo?.val の型は undefined|number になるため、
// tscのstrictNullChecks オプションがtrueの場合 `/` のところでタイプエラーになる。

```

## Nullish Coalescing

```ts
let x = foo ?? bar();

// equivalent to
let x = (foo !== null && foo !== undefined) ?
    foo :
    bar();
```

`foo` が `null` か `undefined` の場合のみ、右の式が評価されて全体の値になる。

`||` との違い: `||` は左が `0` `NaN` `''` の場合でも右の式を評価してしまう。

## Assertion Functions

TS3.7以前、assertion関数 (特定の条件が満たされなければthrowする) の型をうまく表現できなかった。

TS3.7から、関数戻り値のところに `asserts CONDITION`書くことで、"例外投げなければconditionが成り立つ" とコンパイラに保証することができるようになる。

```ts
// 文法:
function foo(x: unknown): asserts CONDITION {}

// CONDITIONの例
function assertIsStr(x: unknown): asserts x is string {
    if (typeof x !== 'string') throw ...;
}

function bar(x: unknown) {
    assertIsStr(x);
    // ここまで来れたら、CONDITION ("x is string") が成立するとされる
    return x.toUppercase();
}
```

## Better Support for `never`-Returning Functions

```ts
// 戻ることがない関数専用の戻り値: never
// (でも型推論で自動でneverにならないみたい、自分でneverを指定することが必要)
// node.jsのTS型宣言に、process.exit() もnever型を返す
function neverReturn(): never {
    throw new Error();
}

// TS3.7以前に、neverを返す関数を呼び出しても、コントロールフロー分析が「戻らないこと」を意識しなかった
function foo() {
    neverReturn();
    return 1; // TS3.7から、ここが unreachable code になる
}

```

## (More) Recursive Type Aliases

TS3.7以前、Type Alias (おそらくMapped Type含めて) に（直接・間接ともに）再帰的にType 使うと妙なエラーが出たりしてた。

TS3.7から、↓のように「再帰Readonly」みたいな型を簡単に書けるようになる。

```TypeScript
export type DeepReadonly<T> = T extends (string | number | symbol | null | undefined | void | RegExp | Function)
  ? T
  : T extends Map<infer K, infer V>
  ? ReadonlyMap<K, V>
  : T extends Set<infer E>
  ? ReadonlySet<DeepReadonly<E>> // pre-3.7: Type "DeepReadonly" is not generic
  : T extends Array<infer E>
  ? readonly DeepReadonly<E>[]   // pre-3.7: Type "DeepReadonly" is not generic
  : T extends {}
  ? { readonly [k in keyof T]: Readonly<T[k]> }
  : never;

```

## --declaration and --allowJs

TS3.7以前、tscの `allowJs` オプションで JSをコンパイル (トランスパイル) する場合、`.d.ts` を生成できなかった。

TS3.7から、入力がjsでもtscが推論したタイプで `.d.ts` を生成するようになる。

## Uncalled Function Checks / Function Truthy Checks

TS3.7から、関数型の値 `foo` を呼び出さずに `if (foo) { ... } ` のように書くと、コンパイルエラーが出るようになる。(メソッド呼び出しも同様。具体のエラー条件と回避方法は元のポストに)

## `// @ts-nocheck` in TypeScript Files

TS3.7から、このコメントがTSファイルでも効くようになる。

## Build-Free Editing with Project References

`project references` という機能の強化らしい、私使ったことないのでよくわからなかった。

## Semicolon Formatter Option

tscとVS Codeの内蔵フォマート機能の強化らしい、私 `prettier` だけ使ってるのでよくわからなかった。

## と、バグ修正など