Edited at

TypeScript 3.7のOptinal Chainig とNullish Coalescingを使ってみた


概要

昨日、11月8日に待望のTypeScript3.7.2がリリースされましたね!!

何が待望かというと注目されているのは


  • Optional Chaining

  • Nullish Coalescing

だと思います。

勿論、ほかにも追加された機能はありますので公式のリンクを張っておきます。

是非一度読んでみてください!!

https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-7.html

注意:深夜テンション & 酔っているので誤字脱字、日本語が変も知れません。

添削や過不足あれば、ご指摘していただける修正させていただきます。


Optional Chaining

Interfaceを定義する際によくoptionalのプロパティを作成する時は往々に存在します。

プリミティブな型にoptionalならまだ良いのですが、

optionalがnestしまくっていると、各階層で検査が必要になりIf文や三項演算子まみれになります。

しかし、Optional Chainingを使えば各階層のoptionalをまとめて検査することが出来ます。


interface

interface Imas {

million?: {
princess? {
matsuri: string
}
}
};

っといったInterfaceが存在している場合、

Matsuriプロパティのvalueを取得するには今までは以下のように取得していました。


typescript


const imas: Imasi = {
million: {
princess: {
matsuri: "HO?"
}
}
};

const ho = imas.million != null && imas.million.princess != null ? imas.million.princess.matsuri ? "HO?";
console.log(ho);
// -> HO?


それがOptional Chainingを使えば以下のように取得出来るようになりました。


typescript


const imas: Imasi = {
million: {
princess: {
matsuri: "HO?"
}
}
};

const ho = imas.million?.princess?.matsuri ?? "HO?";
console.log(ho);
// -> HO?


これの登場により型安全且つ、今までよりは完結にアクセス出来るようになりました。

ここで1つ疑問があります。

union型となっているプロパティへの判定の仕方です。

公式ドキュメントでは以下のように記述されていました。


You might find yourself using ?. to replace a lot of code that performs repetitive nullish checks using the && operator.

// Before

if (foo && foo.bar && foo.bar.baz) {
// ...
}
// After-ish
if (foo?.bar?.baz) {
// ...
}

Keep in mind that ?. acts differently than those && operations since && will act specially on “falsy” values (e.g. the empty string, 0, NaN, and, well, false), but this is an intentional feature of the construct. It doesn’t short-circuit on valid data like 0 or empty strings.


このことからnullとunderstandのみ判定しているので空文字列、0、falseはtrueと判断され次のプロパティにアクセスしてくれます。

これの登場によりIf文や三項演算子のnestがかなり軽減されると思います。

注意点としてはoptionalの型に対してしか出来ない為、Mapの.get()等では使えませんでした。

あくまでoptionalの型のみなのです!!


Nullish Coalescing

JavaScriptの現場では以下のコードを良く見ると思います。


javascript


var ho = matsuri || "HO?";

これは以下コードと同義になります。


javascript


var ho = matsuri ? matsuri : "HO?";

一見良さそうに見えるのですが、TypeScriptを使う現場では結構地雷だと思っています。

なぜかと言うと、

型情報から見れば空文字列も0もfalseはnull、understand とは全くの別物

だからです。

null、undefinedは経緯が違うものの、valueが存在しないのは確かですが、

空文字列、0、falseはvalueが存在しているからです。

今までnull、undefinedとそれ以外を判定する場合は以下記述が最も有力だと思っています。


typescript


const ho = matsuri != null ? matsuri : "HO?";

しかし3.7以降からは以下で判断出来ます。


typescript


const ho = matsuri ?? "HO?";

一見そんなに変わらないように見えますがこれのより良いところは遅延評価しており、falseに関数を入れても出来ることもできパフォーマンスもほぼ遜色なく下手したら良くなるまであります。

scalaで言うところのlazyに近いですかね?

つまりは判定結果がtrueであれば後続処理が行われない為、パフォーマンスが今までより少しは良いとされます。

これの登場にとり値がなかった場合

デフォルト値を返却するといった関数はいらないどころかある種のパフォーマンス改善にもなるかもです。

あまり変わらないといったクレームは聞きません。


最後に

いかがでしょうか?

TypeScriptの現場の方やいずれフロントやるかもって人には価値があると思っています。

現に今の現場ではほぼ一存で導入してもらいましたが良い意味で結構変わると思っていますし、

自分はそれを既に感じているのでこれからより良く方向に変わると思っています。

もしこの記事をTypeScriptの現場の方が読んでいてあなたにライブラリアンではない場合、

個人的には労力を使ってでも導入する価値はあると思っています。

この記事にいいねがいっぱいつけばより価値があがるので説明にも使えるかもです。

是非いいねを!!

TypeScriptに関わっていない人に価値のない記事です。

また、ここまで読んでくれたら普通に嬉しいです。

ついでにいいねもお願いします(恩着せがましい)

最後まで読んでいただいてありがとうございます。

添削や過不足あれば、お気軽にご指摘ください。