LoginSignup
19
7

More than 3 years have passed since last update.

【TS】TypeScript 4.0 の新機能

Last updated at Posted at 2020-08-21

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

Variadic Tuple Types

説明するのは、すごく難しい!!!

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

例えば

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

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

こんな使い方もある

もっとスムーズに型が定義できる
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]

だから何? どこが便利?


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

型定義を汎用化に

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をさっそく使いこなす

Labeled Tuple Elements

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

// 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

Class Property Inference from Constructors

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

タイプ自動判断
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 (!) 、ビックリマークを付けることで、初期化済みと見なし

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

新しい演算子が追加されました。 &&=||= 、??=

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

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

// "QQ Equals"
a ??= b;
a ?? (a = b);
遅延初期化
let values: string[];

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

// After
(values ??= []).push("hello");
遅延初期化
obj.prop ||= foo();

// 下記いずれと同じ

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

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

unknown on catch Clause Bindings

現状 catchany を設定していますが、何でもできじゃうから、ちょっと危険ですね

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

/** @deprecated */ Support

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

t

参考資料

19
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
19
7