Effective TypeScript を読む(1)
TypeScript を書いている割に理解が薄いのでちょっと勉強した。
Effective TypeScript を読みながらメモを取っていく。 JavaScript と明記されていないコードはすべて TypeScript である。
JavaScript と TypeScript の関係
自分は TypeScript は 型がついた JavaScript の上位集合みたいな認識でいる。 すべての JavaScript は TypeScript だけど、すべての TypeScript が JavaScript ではない。
JavaScript のコードを TypeScript の型チェックにかけるとエラーが出が、トランスパイルはされる。 そのため、エラーが出たからといって実行できないわけではない。
TS -> JS
function asNumber(val: number | string): number {
return val as number;
}
console.log(asNumber('1') + asNumber(2)); // 12
function asNumber(val) {
return val;
}
console.log(asNumber('1') + asNumber(2)); // 12
as <hogehoge>
はキャストではないので、string
に対し as number
をしていてもエラーは出ない。
asNumber(val)
は number
を返すので、1 + 2 が計算され console.log
では 3 を出力しそうだがそうならない。
トランスパイルされた JavaScript では型に関するコードがなくなり、asNumber(val)
は引数をそのまま戻り値にする意味のない関数になっている。
TypeScript の型は JavsScript になったら消えるので、実行時にnumber
かstring
かを見て操作を切り替えたいなら、以下のように書く。
function asNumber(val: number | string): number {
return typeof(val) === 'string' ? Number(val) : val;
}
typeof
クラスの型によって処理を変えるとき、typeof
を使って実現することはできない。
class Class {
constructor() {}
}
const c = new Class();
console.log(typeof(c)); // object
var Class = /** @class */ (function () {
function Class() {
}
return Class;
}());
var c = new Class();
console.log(typeof (c));
TypeScript の世界に存在する class
は、 JavaScript の世界で動く typeof
にとって単なるオブジェクトである。
型は実行時には(トランスパイルすると)消えてしまう。型は実行に何の影響も与えない。
Structural typing
class C {
foo: string;
constructor(foo: string) {
this.foo = foo;
}
print() {
console.log(this.foo);
}
}
const c: C = new C("C");
c.print(); // C
const d: C = { foo: "D", print() { console.log("bar") } };
d.print(); // bar
c
と d
は両方とも C
型だが挙動が違う。d
はクラス C
と構造が同じなので、型エラーは起きない。
JavaScript のダックタイピングが TypeScript では Structural typing になった、みたいな感じ?
必要がなければ any を避ける
let num: number;
num = '12' as any;
num += 1;
console.log(num); // 121
as any
を使うと型が一致していなくても割り付けられる(エラーが出ない)。
型が any
だと補完が効かなくなったり、IDEのリファクタリング(プロパティ名の rename など)で問題が起きる場合もあるので、理由がなければ使わない方が良い。
感想
チャプター 1 なのでそこまで踏み込んだ話はない。