ごあいさつ
社内で TypeScript の話題を聞くようになったので、
ちょうど業務で触れる機会のあった自分が主に気になった点を共有したいと思います。
試したい方は
実際ハンズオン的に触りたい方は、各所で導入方法が紹介されていますので、そちらを参考に。
VSCodeとnodejsをインストールするのを皮切りに、いくつかコマンド叩けばすぐ動くものが試せます。
オブジェクトのAny問題
TSはJSをそのまま書けます。
JSのつもりでオブジェクトを定義しようとすると、以下のように書きがちです。
const obj = {};
obj.foo = "bar"; //エラーとなる
しかし、このままではVisual Studioなんかではエラーになっちゃうんです。
"obj"は型が未指定だから"foo"なんてプロパティは無いよ、と。
最も簡単な回避方法はanyを指定することです。
const obj:any = {};
anyというのは「型を指定できる」TSにおいて、「型の指定を行わない」と宣言するようなもので、一般的にはアンチパターンです。
オブジェクトやArrayの型指定は用意されています。
const obj : { [s: string]: string } = {}; // 任意の文字列Keyで文字列Valueのオブジェクト
安易にanyに逃げないで行きたいところです。
オブジェクトValueの型不一致問題
さぁ、上記でオブジェクトは正しく定義できるようになったんですが、下記のようなJSONがあったらどうでしょう。
{
name : "太郎",
age : 25
}
ageの型はNumberなので"{ [s: string]: string }"としてしまうと不都合があります。
こういった場合は下記のように書けます。
const obj : { [s: string]: string | number } = {};
パイプでつないでORみたいにできるイメージですかね。
Valueの型が複数あるオブジェクトから取得問題
さぁ、上記で型が複数あるオブジェクトも定義できました。
しかし、そういったオブジェクトから値を取得するときにまたまた問題が見つかります。
const json='{name:"太郎",age:25}'
const obj: { [s: string]: string | number } = JSON.parse(json);
const ageMinus = obj.age - 1; // エラーとなる
上記の例だと、ageプロパティが"string | number"型なので四則演算できないよ、みたいなことを言われます。
下記のようにするとageがnumberであると明示的に指定でき、エラーが解消できます。
const ageMinus = <number>obj.age - 1;
なんかいろいろ複雑になってきますね。
やりすぎて見通しが悪くなるようなら、無理にanyを駆逐しない、という選択肢も考慮しても良いかもしれません。
TSの本質に潜む罠
根本的な話に戻りますが、TSはあくまでJSを生成するものです。
つまり TSで書いてもあくまで動作するのはJS なのです。
当たり前と思うかもしれませんが、こなれて来たとき私はこの事実に面食らいました。
具体的に言うと、気を付けて書かないと、privateな(そのClass内からしかアクセスできない)classもfunctionもいくらでも外部からアクセスできるのです。
TSは、privateなClassなfunctionを書くことができます。
実際、そういったClassやfunctionを外部から呼ぶような実装を書くと、Visual Studio等の高度なIDE・エディタであれば、その時点でエラー表示されます。
でもそれは、記述する上での制約が効いているだけであり、出来上がったJSのClassやfunctionはprivateでもなんでもなかったりするのです。
だって、Javascriptにはそんな機能ない のだから。
一応、関数で括る(いわゆるクロージャってやつかな?)などの措置をとれば同様のことはできますが、
直観的には「privateと書いたものはprivateになっている」と思ってしまいがちです。
これに関しては、以前議論されているstackoverflowやissuesを見かけたので、そのうち是正されるかもしれません。
以上
なんか文字が多くなっちゃいましたが、TS初心者がハマった記録として共有させていただきます。