理系学生日記

おまえはいつまで学生気分なのか

「プログラミングTypeScript」を読んだ

プログラミングTypeScriptを読みました。

TypsScript

最近はどこも、JavaScript書くんだったらTypeScript書いてトランスパイルという状況になってきている印象があります。

僕自身はJavaScriptそのものに苦手意識(言語的な好き嫌いという話ではなく、単にスキル不足)があり、ずっと二の足を踏んでいました。 ただし以下のような状況もあり、少しずつキャッチアップしていくべきだろうと考えるに至りました。

  • Azureと関わっている上でTypeScriptの親和性が高そう
  • 今後モバイル周りを開発していく場合もTypeScriptが選択肢になりそう
  • フロントエンドを開発するにしても、素のJavaScriptを使っていると生産性が悪そう

TypeScriptのメリットというと、それはやはり型なのでしょう。

TypeScriptの使用を選択した場合、期待されるメリットには以下のものがあります。

  1. 静的な型チェック。コンパイル時に一部の型エラーを検出することができます。
  2. より高性能なエディタ機能。リネーム、定義クエリおよび自動補完など。
  3. 一目瞭然の型宣言。プログラムコードの読みやすさの向上。
  4. 他人が使用するためのライブラリを開発する場合は、型定義の提供によりユーザの開発エクスペリエンスを向上可能。

今回の書籍についても、その型定義の機能性、柔軟さには目を見張るものがありました。 Generics抽象クラスなど、Javaに近しい機能を持つのでわかりやすい一方、より高度なオブジェクト型も提供してくれています。

例えば、以下に示すようなマップ型の応用例からわかる表現力、そしてそれらを実現するPartial<Type>等の組み込み型は強力に感じます。

type Account = {
    id: number
    isEmployee: boolean
    notes: string[]
}

// すべてのフィールドを省略可能にします
type OptionalAccount = {
    [K in keyof Account]?: Account[K]
}

// すべてのフィールドをnull許容にします
type NullableAccount = {
    [K in keyof Account]: Account[K]: null
}

また、TypeScriptの型システムは構造的である一方、名前的型の実現も可能です。

Type compatibility in TypeScript is based on structural subtyping. Structural typing is a way of relating types based solely on their members.

TypeScript: Documentation - Type Compatibility

ここではコンパニオンオブジェクトパターンType Assertionが組み合わされ、名前的型を実現しています。

type CompanyID = string & {readonly brand: unique symbol}
type OrderID = string & {readonly brand: unique symbol}
type UserID = string & {readonly brand: unique symbol}
type ID = CompanyId | OrderId | UserId

function CompanyId(id: string) {
    return id as CompanyID
}

function OrderID(id: string) {
    return id as OrderID
}

function UserID(id: string) {
    return id as UserID
}

書籍中には「このアプローチはやりすぎ」という記載がありますが、このような柔軟性は言語として魅力に感じます。

全体通して

定義だけでもかなり表現の幅が広い一方で、それを「実践」の域まで理解するには実際にコードを記述していく必要性を強く感じました。積極的に機会を見つけ、遊んでいきます。