JSX の型を整理してみた
JSX の型はかなり複雑なことになっている気がしたので、整理してみました。
プリミティブ型、オブジェクト型、可変型、未定義許可型
JSX における型は、この 4 種類に分類されるらしいです。
プリミティブ型
プリミティブ型は現在、
- boolean
- int
- number
- string
の 4 種類があります*1。
これらの型を持つ変数には null を入れることができません。
var x: int = null; // compile error!
また、これらの型の値は変更不可能 (イミュータブル) となります。
3 がいつの間にか 4 に変わっていたりしてほしくないですよね?
"hoge" という文字列の o という文字がいつの間にか a に変わっていて "hage" とか悲しいですよね?
これらの型の値では、そのようなことは起こりません。
オブジェクト型
オブジェクト型は例えば、
- string 配列
- 関数
- Date
- Object
などが該当します。
class などによりユーザが定義する型は全てオブジェクト型となります。
プリミティブ型とは違い、これらの型を持つ変数には null を入れることができます。
var xs: int[] = null; // OK
また、プリミティブ型とは違い、オブジェクト型は全てがイミュータブルというわけではありません。
class ImmutableSample { var _x: int; function constructor(x: int) { this._x = x; } function x(): int { return this._x; } } class MutableSample { var _x: int; function constructor(x: int) { this._x = x; } function x(): int { return this._x; } function setX(x: int): void { this._x = x; } }
この例では、ImmutableSample のオブジェクトに対しては (_で始まるメンバにはアクセスしない、という約束事を守ると) 生成後にその状態を変更することはできません。
それに対して、MutableSample のオブジェクトに対しては、setX を呼び出すことで生成後にオブジェクトの状態を変更することができます。
可変型
可変型はコンパイル時に定まらない型のために用意されています。
この型の変数には null を入れることが可能です。
チュートリアルには、「この型の値に対してできるのは同じかどうかの判定だけで、何かやりたければキャストが必要になる」というようなことが書いてあります。
が、現在はプロパティアクセスなら許しているようです。
プロパティアクセスも禁止するようになったようです。不便になったと感じるかもしれませんが、自分としてはプロパティアクセスも不可の方が正しいと思います。
JavaScript とちがい、typeof 演算子は可変型のみに許されています*2。
また、可変型を表すキーワードには variant を使います。個人的には any 型とか別の言葉を使ってほしかったところです。
可変型は null を扱えますので、こんなことも可能です。
var v: variant = null; var i: int = v as int; log i; // => 0
boolean の場合 false に、string の場合は null という文字列に変換されるようです。
string の場合は空文字列とかになってほしいような気もします。
未定義許可型
未定義許可型は、未定義 (undefined) という値を取りうる唯一の型です*3。
例えば、0 での割り算を undefined にしたい場合、
static function div(a: int, b: int): MayBeUndefined.<int> { if (b == 0) return undefined; return a / b; }
このように、MayBeUndefined.
ただし、この T に MayBeUndefined 自身を指定するとコンパイルエラーになるようです。
また、可変型を指定してもコンパイルエラーとなります。
未定義許可型は、T の扱える範囲に加えて undefined が扱える型ですので、T がプリミティブ型であれば null は扱えませんし、オブジェクト型であれば null も扱える、という非常に特殊な型となっています。
var x: MayBeUndefined.<int> = null; // コンパイルエラー var y: MayBeUndefined.<Date> = null; // OK
その他特殊な型
JSX の型はプリミティブ型、オブジェクト型、可変型、未定義許可型の 4 種類と書きましたが、これらに (おそらく) 属さない特殊な型や、JSX 処理系によって特別扱いされている型もあります。
配列型
配列はオブジェクト型の属しますが、扱いはかなり特殊です。
配列の型は Array.
また、Array.
このあたり、Java などから入る人には罠だと思います。
これはサイズを指定した配列を作った時に、JavaScript では配列の各要素が undefined で埋められるのが主な原因と思われます。
Array.
それは、T に可変型が指定できることです*4。
未定義許可型の T には可変型が指定できない、と書きましたが、実はできる方の方が特殊なのです。
そのため、JSX では「なんでも入るコレクション」を作ることはできません。
追記:これは自分の勘違いでした。コメント欄参照。
他に不思議なこととして、
var xs = [1, 2, undefined]: int[]; var ys = new int[3]; ys[0] = 1; ys[1] = 2; log xs; // => [ 1, 2, undefined ] log ys; // => [ 1, 2, ]
となります。ううん・・・?
void 型
void 型は値を返さない関数の戻り値に指定します。
それ以外の場所では指定できません。
こんな感じで
JavaScript に引っ張られたりバグなのか仕様なのかよく分からん動きをしたりするので、割と複雑です。
ルールさえわかってしまえばどうということはないのですが、そういう文章が JSX はあまり整備されていませんので、勝手にまとめてみました。