項目3 コード生成は型に依存しないことを理解する
tscが行うこと
tscは下記の2つの動作を独立して行う
トランスパイル
次世代のTypeScript/JavaScriptを古いバージョンのJavaScriptに変換し、実行環境で動作するようにする
コードに型エラーがないかチェック
型チェックは実行時ではできないことに注意
実行時にはTypeScriptの型チェックはできない
TypeScriptの型は、コンパイルされると消去されるため、実行時はただのJavaScriptになる
code:ts
interface Square {width: number;}
interface Rectangle extends Square {height: number;}
type Shape = Square | Rectangle;
function calculateArea(shape: Shape) {
// instanceofによるRectangle型チェックは行えない
if (shape instanceof Rectangle) {
return shape.height * shape.width
} else {
return shape.width * shape.width;
}
}
JavaScriptでも動くかつ、TypeScriptによる型チェックの恩恵も受けることができる
code:ts
function calculateArea(shape: Shape) {
if ('height' in shape) {
return shape.height * shape.width
} else {
return shape.width * shape.width;
}
}
判別可能ユニオンとも呼ばれる
code:ts
interface Square {kind: 'square';width: number;}
interface Rectangle {kind: 'rectangle';height: number;width: number;}
type Shape = Square | Rectangle;
function calculateArea(shape: Shape) {
if (shape.kind === 'rectangle') {
return shape.width * shape.height;
} else {
return shape.width * shape.width;
}
}
クラスを使って対応
クラスを使うことshape instanceof RectangleのRectangleは値として扱われるためJavaScriptで実行可能
code:ts
class Square {...}
class Rectangle extends Square {...}
type Shape = Square | Rectangle;
function calculateArea(shape: Shape) {
if (shape instanceof Rectangle) {...}
}
型エラーがあってもコンパイルできる
コードの出力(コンパイル)は型チェックに依存しないので、型エラーが存在していても実施できる
型アサーションは実行時の値に影響しない
文字列を常に数値として正規化するために、型アサーション(型演算)使っても、実行時には型は消去されるため意味がない code:ts
function asNumber(val: number | string): number {
return val as number;
}
コンパイル後のJSでは以下になる
code:js
function asNumber(val) {
return val;
}
正規化する際は、コンストラクタを使う
code:ts
function asNumber(val: number | string): number {
return Number(val);
}
型アサーションはキャストでない
実行時の型は宣言された型と異なる可能性がある
APIレスポンスの型に、想定している型と異なる型の値が入る可能性があるが、これを強制することはできない
code:ts
interface LightApiResponse {lightSwitchValue: boolean;}
async function setLight() {
const response = await fetch('/light');
// boolean以外の型が入ってくる可能性がある
const result: LightApiResponse = await response.json();
setLightSwitch(result.lightSwitchValue);
}
実行時の型が宣言した型と一致しないことを不健全な型という 型に基づく関数のオーバーロードはできない
1つの関数に複数の型シグネチャを指定できるが、実装は1つでなければならない
コンパイルすると、型が削除され実装だけ残る
型は実行時のパフォーマンスに影響しない
型や型演算は、コンパイル後に削除されるため、実行時のパフォーマンスに影響しない
ただし、2点注意がある
ビルド時のオーバーヘッドが生じる
古いランタイムをサポートしつつコンパイルする場合は、オーバーヘッドが生じる可能性がある
TypeScriptにかかわらず、JavaScriptのトランスパイラーでも同様の問題が発生する