【TS】TypeScript 4.0 の新機能

\:loudspeaker: TypeScript 4.0 がリリースされました。新機能をピックアップし、試していきましょう。

## Variadic Tuple Types
説明するのは、すごく難しい！！！

### 簡単にいうと、`...T` が書ける

例えば

```typescript
type Strings = [string, string];
type Numbers = number[]

// [string, string, ...Array<number | boolean>]
type Unbounded = [...Strings, ...Numbers, boolean];
```

### こんな使い方もある
```typescript:もっとスムーズに型が定義できる
type Foo<T extends unknown[]> = [string, ...T, number];

type T1 = Foo<[boolean]>;  // [string, boolean, number]
type T2 = Foo<[number, number]>;  // [string, number, number, number]
type T3 = Foo<[]>;  // [string, number]
```

### だから何？ どこが便利？

```typescript

declare function hello(name: string, msg: string): void;
// 上記と同じです
declare function hello(...args: [string, string]): void;

// もっと活用しましょう
declare function h(a: string, b: string, c: string): void

// 同じです！
declare function h(a: string, b: string, ...r: [string]): void
// 同じです！！
declare function h(a: string, ...r: [string, string]): void
// 同じです！！！
declare function h(...r: [string, string, string]): void
```

### 型定義を汎用化に

```typescript:HasCallback
type HasCallback<T extends unknown[]> = 
      (...t: [...T, (...args: any[]) => any]) => void;

declare const foo: HasCallback<[string]>

foo('hello', function() {}) // 👍
foo('hello') // 💥 breaks

declare const bar: HasCallback<[string, number]>

bar('hello', 2, function() {}) // 👍
bar('hello', function() {}) // 💥 breaks
bar('hello', 2) // 💥 breaks
```

### もっと詳しく
こちらはおすすめです。
**[TypeScript 4.0で導入されるVariadic Tuple Typesをさっそく使いこなす
](https://qiita.com/uhyo/items/7e31bbd93a80ce9cec84)**

## Labeled Tuple Elements
従来の配列定義は、タイプのみとなりますが、現在ラベル付けることができます。

```typescript
// before 
type Range = [number, number];

// after
type Range = [start: number, end: number];

// other sample
type Foo = [first: number, second?: string, ...rest: any[]];

type Bar = [first: string, number];
//                         ~~~~~~
// Error! ラベルは、一部のみ付けることはエラーとなります
```

### Dynamic Function Parameter Definition

![image](https://devblogs.microsoft.com/typescript/wp-content/uploads/sites/11/2020/08/signatureHelpLabeledTuples.gif)

## Class Property Inference from Constructors
Class の `constructor` 関数のパラメータから、Class 属性のタイプを自動的に判断できるのものです。

```typescript:タイプ自動判断
class Square {
    // 旧: any, 新: number
    sideLength;

    constructor(sideLength: number) {
        if (Math.random()) {
            this.sideLength = sideLength;
        }
    }

    get area() {
        return this.sideLength ** 2;
        //     ~~~~~~~~~~~~~~~
        // error! Object is possibly 'undefined'.
    }
}
```

本来は `undefined` のところで、`definite assignment assertion (!)` 、ビックリマークを付けることで、初期化済みと見なし

```typescript
class Square {
    // definite assignment assertion
    //        v
    sideLength!: number;
    //         ^^^^^^^^
    // type annotation

    constructor(sideLength: number) {
        this.initialize(sideLength)
    }

    initialize(sideLength: number) {
        this.sideLength = sideLength;
    }

    get area() {
        return this.sideLength ** 2;
    }
}
```


## Short-Circuiting Assignment Operators
新しい演算子が追加されました。 `&&=` 、 `||=`　、`??=`

```typescript:簡単例
// "Or Or Equals"
a ||= b;
a || (a = b);

// "And And Equals"
a &&= b;
a && (a = b);

// "QQ Equals"
a ??= b;
a ?? (a = b);
```

```typescript:遅延初期化
let values: string[];

// Before
(values ?? (values = [])).push("hello");

// After
(values ??= []).push("hello");
```

```typescript:遅延初期化
obj.prop ||= foo();

// 下記いずれと同じ

obj.prop || (obj.prop = foo());

if (!obj.prop) {
    obj.prop = foo();
}
```


## unknown on catch Clause Bindings
現状 `catch` は `any` を設定していますが、何でもできじゃうから、ちょっと危険ですね


```typescript
try {
    // ...
}
catch (e: unknown) {
    // error!
    // 'unknown' type には、'toUpperCase' の属性が存在しない
    console.log(e.toUpperCase());

    if (typeof e === "string") {
        // works!
        // type 限定すれば、使えます。変換は必要ない
        console.log(e.toUpperCase());
    }
}
```

## Editor Improvements
### Convert to Optional Chaining
![image](https://devblogs.microsoft.com/typescript/wp-content/uploads/sites/11/2020/08/convertToOptionalChain-4-0.gif)

### /** @deprecated */ Support
`/** @deprecated *` をドキュメントに付けると、取り消し線が表示されます。

![t](https://devblogs.microsoft.com/typescript/wp-content/uploads/sites/11/2020/06/deprecated_4-0.png)

## 参考資料
https://devblogs.microsoft.com/typescript/announcing-typescript-4-0/