フリーダムの日記

GIS(地理情報システム)を中心に技術的なことを書いています。

プログラミング TypeScript:第 3 章 型について

はじめに

本記事では「プログラミング TypeScript ―スケールする JavaScript アプリケーション開発」について自身の学習も含めて、数回に渡って紹介しています。

プログラミングTypeScript ―スケールするJavaScriptアプリケーション開発

プログラミングTypeScript ―スケールするJavaScriptアプリケーション開発

  • 作者:Boris Cherny
  • 発売日: 2020/03/16
  • メディア: 単行本(ソフトカバー)

前回は、プログラミング TypeScript:第 2 章 TypeScript 全体像について紹介しました。

freedom-tech.hatenablog.com

今回は、第 3 章の型について紹介していきます。

また、学習用にサンプルプログラミングも Github で紹介していますので、合わせて紹介しています。 github.com

型について

実は、前回の章でも型システムの概念は紹介していましたが、型システムにおける「型」が実際に何を意味するのかを定義していませんでした。

型 (type) :値と、それを使ってできる事柄の集まり

これだと理解しづらいかもしれないので、例をいくつか挙げます。

  • boolean 型は、すべてのブール値 (true と false の2つだけです)と、それらについて行うことのできる演算や操作 (||、&&、!など)の集まりです。
  • number 型は、すべての数値と、それらについて行うことのできる演算や操作 (+、-、*、/、%、||、&&、?など)の集まりです。これには、.to.Fixed、.toPrecision、.toString など、それらについて呼び出すことのできるメソッドも含まれます。
  • string 型は、すべての文字列と、それらについて行うことのできる演算や操作 (+、||、&& など) の集まりです。これには、.concat や .toUpperCase など、それらについて呼び出すことのできるメソッドも含まれます。

あるものの型が T であることを目にした場合、単にそれが T であることが分かるだけでなく、その T を使って「具体的に何ができるのか」(および何ができないのか)が分かるのです。肝心なのは、型チェッカーを使って、不正なことをしてしまうのを防ぐことです。そして型チェッカーが、何が正しくて何が正しくないかを知る方法、あなたが使っている型と、それらをあなたがどのように使っているかを調べることです。
以下の図は、TypeScript の型の概観を示しています。図が示すように多くの型を使用することができます。

f:id:freedom0625:20200628101732p:plain

ここでは、型の詳細については他のWebサイトなどを参照していただき、練習問題を中心に紹介しています。
各型の詳細については、以下のサイト等をご参照ください。 js.studio-kingdom.com github.com

TypeScript にプログラムの値から型を推論させることができますし、プログラマーが値を明示的に型付けすることもできます。const を使うと、TypeScript はより具体的な型を推論し、let や var を使うと、より一般的な型を推論します。多くの型には、より一般的なものと、それに対応するより具体的な物があり、後者は前者のサブタイプです。

表 さまざまな型とそれらのより具体的なサブタイプ

サブタイプ
boolean 真偽値リテラル
bigint BigInt リテラル
number 数値リテラル
string 文字列リテラル
symbol unique symbol
object オブジェクトリテラル
配列 タプル
enum const enum

練習問題

  1. 次のそれぞれの値について、TypeScript はどのような型を推論するでしょうか?
// a
let a = 1042 // number

// b
let b = 'apples and oranges' // string

// c
const c = 'pineapples'   // 'pineapples'

// d
let d = [true, true, false]  // boolean[]

// e
let e = {type: 'ficus'}  //  {type: string}

// f
let f = [1, false]  //  (number | boolean)[]

// g
const g = [3]  //  number[]

// h
let h = null  // any
  1. 次のそれぞれのものは、なぜエラーをスローするのでしょうか?
// a
let i: 3 = 3
i = 4 // エラー TS2322: 型 '4' を型 '3' に割り当てることはできません。

/*
回答:iの型はリテラル型の3です。4の型はリテラル型の4であり、これをリテラル型の3に割り当てることはできません。
*/

// b
let j = [1, 2, 3]
j.push(4)
j.push('5') // エラー TS2345: 型 '"5"' の引数を型 'number' の
                  // パラメーターに割り当てることはできません。

/*
回答:j は number のセットを使って初期化されたので、TypeScript は j の型を number[] と推論しました。'5' の型はリテラル型の '5' であり、これを number に割り当てることはできません。
*/

// c
let k: never = 4 // エラー TS2322: 型 '4' を型 'never' に
                          // 割り当てることはできません。

/*
回答:never はボトム型です。つまり、never を他のすべての型に割り当てることはできますが、never にはどの型も割り当てることができません。
*/

// d
let l: unknown = 4
let m = l * 2 // エラー TS2571: オブジェクトの型は 'unknown' です。

/*
unknown は、実行時に何にでもなりうる値を表します。あなたがしていることが安全であることを TypeScript に示すには、まず、unknown型の値が、実際にはより具体的なサブタイプを持っていることを TypeScript に示す必要があります。これを行うには、typeof、instanceof、または他の型クエリーや型ガードを使って値を絞り込みます。
*/

さいごに

今回は型を中心でしたが、次は関数です。次回もなるべく要点を絞って紹介していければと思います。