TL;DR
- TypeScript のシンボルは、型空間と値空間のどちらかに属する。型空間のコードは JavaScript に変換すると消える。
classやenumのように両方の空間に導入される構文や、typeofのように空間によって意味が変わる構文がある。
内容
型空間と値空間
型空間のコードは JavaScript のコードには残らないので(型消去)、TS Playground で生成される JavaScript を確認すると、型空間と値空間を見分ける直感を養える。
すべての値には静的な型があるが、型には型空間からしかアクセスできない。type や interface のような型空間の構文は、変換時に消える。
一方、class や enum のように、型と値の両方を導入する構文もある(enum はなるべく使わない:項目72)。次の例では、Cylinder を値として instanceof に使い、その結果 shape の型が Cylinder に絞り込まれる。
class Cylinder {
radius: number
height: number
constructor(radius: number, height: number) {
this.radius = radius
this.height = height
}
}
function calcVolume(shape: unknown) {
if (shape instanceof Cylinder) {
shape // shape: Cylinder
shape.radius // shape.radius: number
}
}空間によって意味が変わる構文
次の構文は、型空間と値空間で意味が変わる。
| 構文 | 値空間 | 型空間 |
|---|---|---|
typeof | 実行時の型を表す文字列を返す | 値を受け取り、TypeScript の型を返す |
[] | obj['field'] と obj.field のどちらでもプロパティを参照できる | Person['first'] のようにブラケット記法を使い、中に型を入れる |
this | JavaScript の this | メソッドの戻り値で自身を指す this 型 |
&、\| | ビット AND とビット OR | インターセクション型とユニオン型 |
const | 新しい変数を宣言する | as const で、リテラルやリテラル式の推論される型を変える |
extends | サブクラスを定義する | サブタイプやジェネリック型の制約を定義する |
in | for (key in object) のループ | マップ型 |
! | 論理 NOT 演算子 | 非 null アサーション |
値空間の typeof が返すのは、'string'、'number'、'boolean'、'undefined'、'object'、'function'、'symbol'、'bigint' のどれかで、TypeScript の型とは異なる。
型空間の [] には型を入れるので、ユニオン型や number も使える。
const first: Person["first"] = jane["first"]
type PersonEl = Person["first" | "last"]
type Tuple = [string, number, Date]
type TupleEl = Tuple[number]値空間の this についてはJavaScript の this(項目69)を参照する。型空間の this 型(polymorphic this type)は、サブクラスでメソッドチェーンを実装するときに便利である。そのほか、as const は項目20、マップ型は項目15、非 null アサーションは項目9で扱う。