2021-11-20

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
JavaScript
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 になったら消えるので、実行時にnumberstringかを見て操作を切り替えたいなら、以下のように書く。

function asNumber(val: number | string): number {
	return typeof(val) === 'string' ? Number(val) : val;
}

typeof

クラスの型によって処理を変えるとき、typeofを使って実現することはできない。

typeof - JavaScript | MDN

class Class {
	constructor() {}
}

const c = new Class();
console.log(typeof(c)); // object
JavaScript
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

cd は両方とも 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 なのでそこまで踏み込んだ話はない。