TypeScript の明示的な型指定と型推論
TypeScriptでは、型を扱うための2つの主要な方法が提供されています。
- 明示的な型指定 (Explicit Typing): 開発者が変数の型を明示的に宣言します。
- 型推論 (Type Inference): 代入された値に基づいて、TypeScriptが自動的に型を決定します。
1. 各アプローチの使い分け
明示的な型指定を使用すべきケース:
- 関数の引数(パラメータ)と戻り値の型
- オブジェクトリテラル
- 初期値と最終的な型が異なる可能性がある場合
型推論を使用すべきケース:
- 値を即座に代入するシンプルな変数宣言
- 文脈から型が明らかな場合
2. 明示的な型アノテーション
明示的な型指定とは、変数がどの型であるべきかをTypeScriptに正確に伝えることを意味します。
2.1 基本的な明示的型指定
// 文字列型 (String)
let greeting: string = "こんにちは、TypeScript!";
// 数値型 (Number)
let userCount: number = 42;
// 論理値型 (Boolean)
let isLoading: boolean = true;
// 数値の配列 (Array of numbers)
let scores: number[] = [100, 95, 98];ベストプラクティス: 関数の引数と戻り値には明示的な型指定を使用しましょう。これにより、コードの保守性が向上し、コード自体がドキュメントとしての役割(自己文書化)を果たすようになります。
2.2 明示的な型指定を用いた関数
// 引数と戻り値に型を明示的に指定した関数
function greet(name: string): string {
return `こんにちは、${name}さん!`;
}
// TypeScriptは正しい引数の型が渡されているかチェックします
greet("アリス"); // OK
greet(42); // エラー: 型 '42' の引数を型 'string' のパラメータに割り当てることはできません3. 型推論 (Type Inference)
TypeScriptは、変数の初期値に基づいて自動的に型を決定(推論)することができます。
3.1 基本的な型推論
// TypeScriptは 'string' 型と推論します
let username = "alice";
// TypeScriptは 'number' 型と推論します
let score = 100;
// TypeScriptは 'boolean[]' 型と推論します
let flags = [true, false, true];
// TypeScriptは戻り値を 'number' 型と推論します
function add(a: number, b: number) {
return a + b;
}注意: 型推論は、変数が宣言と同時に初期化される場合に最も効果的に機能します。初期化せずに宣言された変数は、tsconfig.json で strictNullChecks を有効にしていない限り、デフォルトで any 型になります。
4. 型推論が威力を発揮する場面
4.1 オブジェクトリテラルの推論
// TypeScriptはオブジェクトの形状(シェイプ)を推論します
const user = {
name: "アリス",
age: 30,
isAdmin: true
};
// TypeScriptはこれらのプロパティが存在することを知っています
console.log(user.name); // OK
console.log(user.email); // エラー: プロパティ 'email' は存在しませんチェックポイント: 型推論は非常に便利ですが、特に大規模なコードベースや公開APIを開発する場合は、型を明示することで保守性を高めることができます。
5. 実戦での型安全性
TypeScriptの主な利点の1つは、開発中に型関連のエラーをキャッチできることです。一般的なミスをTypeScriptがどのように防いでくれるか見てみましょう。
5.1 型の不一致エラー(明示的)
let username: string = "alice";
username = 42; // エラー: 型 'number' を型 'string' に割り当てることはできません5.2 型の不一致エラー(暗黙的/型推論)
let score = 100; // TypeScriptは 'number' と推論
score = "high"; // エラー: 型 'string' を型 'number' に割り当てることはできません6. JavaScript と TypeScript の比較
JavaScriptでは、以下のコードはエラーなしで実行されますが、バグの原因になる可能性があります。
6.1 JavaScriptの挙動
// これは有効なJavaScriptですが、バグを招く可能性があります
function add(a, b) {
return a + b;
}
console.log(add("5", 3)); // "53" が返る (文字列の結合)TypeScriptは、これらの問題をコンパイル時にキャッチします。
6.2 TypeScriptによる型安全性
function add(a: number, b: number): number {
return a + b;
}
console.log(add("5", 3)); // エラー: 型 'string' の引数を型 'number' のパラメータに割り当てることはできません7. TypeScriptが型を推論できない場合
TypeScriptの型推論は強力ですが、正しい型を決定できないケースもあります。そのような場合、TypeScriptは型チェックを無効にする any 型にフォールバックします。
注意:any 型やその他の特殊な型については、次の章で詳しく説明します。
7.1 any になる一般的なケース
// 1. JSON.parse は、コンパイル時に構造が不明なため 'any' を返します
const data = JSON.parse('{ "name": "アリス", "age": 30 }');
// 2. 初期化せずに宣言された変数
let something; // 型は 'any'
something = 'こんにちは';
something = 42; // エラーになりません8. 可能な限り any を避ける
any を使用すると、TypeScriptの型チェックが無効になってしまいます。代わりに、以下の代替案を検討してください。
- 型アノテーションを使用する
- 複雑なオブジェクトにはインターフェース (Interfaces)を作成する
- 実行時の型チェックには型ガード (Type Guards)を使用する
tsconfig.jsonでnoImplicitAnyを有効にする