TypeScript 速習チュートリアル

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.jsonstrictNullChecks を有効にしていない限り、デフォルトで 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.jsonnoImplicitAny を有効にする