型システム
プログラムの正しさを保証する仕組み
静的型付け vs 動的型付け
静的型付け
コンパイル時に型チェック。実行前にエラーを発見。
Go, Rust, TypeScript, Java
動的型付け
実行時に型チェック。柔軟だがランタイムエラーのリスク。
Python, Ruby, JavaScript
強い型付け vs 弱い型付け
強い型付け
暗黙の型変換を制限。明示的な変換が必要。
Python, Go, Rust
弱い型付け
暗黙の型変換が発生。予期しない結果の可能性。
JavaScript, C
1 // JavaScriptの弱い型付け例 2 "5" + 3 // "53" (文字列連結) 3 "5" - 3 // 2 (数値演算) 4 [] + {} // "[object Object]" 5 {} + [] // 0
型推論
コンパイラが文脈から型を自動的に推論。明示的な型注釈を減らしつつ型安全性を維持。
1 // Go - 型推論 2 x := 42 // int と推論 3 y := "hello" // string と推論 4 z := []int{1,2,3} // []int と推論 5 6 // 明示的な型宣言 7 var a int = 42 8 var b string = "hello"
1 // TypeScript - 型推論 2 const x = 42; // number 3 const y = "hello"; // string 4 const arr = [1, 2, 3]; // number[] 5 6 // 明示的な型注釈 7 const z: number = 42; 8 const list: string[] = ["a", "b"];
ジェネリクス
型をパラメータ化し、再利用可能なコードを型安全に記述。
1 // Go 1.18+ ジェネリクス 2 func Map[T, U any](slice []T, f func(T) U) []U { 3 result := make([]U, len(slice)) 4 for i, v := range slice { 5 result[i] = f(v) 6 } 7 return result 8 } 9 10 // 使用例 11 nums := []int{1, 2, 3} 12 doubled := Map(nums, func(n int) int { return n * 2 })
1 // TypeScript ジェネリクス 2 function map<T, U>(arr: T[], fn: (item: T) => U): U[] { 3 return arr.map(fn); 4 } 5 6 // 使用例 7 const nums = [1, 2, 3]; 8 const doubled = map(nums, n => n * 2); 9 const strings = map(nums, n => n.toString());
Null安全性
| 言語 | アプローチ | 例 |
|---|---|---|
| Go | ゼロ値 + error | val, err := fn() |
| Rust | Option<T> | Some(val) / None |
| TypeScript | strictNullChecks | T | null | undefined |
| Kotlin | Nullable型 | String? vs String |
1 // Rust - Option型 2 fn find_user(id: u32) -> Option<User> { 3 // ユーザーが見つかればSome、なければNone 4 if let Some(user) = users.get(&id) { 5 Some(user.clone()) 6 } else { 7 None 8 } 9 } 10 11 // 使用時は必ずハンドリングが必要 12 match find_user(123) { 13 Some(user) => println!("Found: {}", user.name), 14 None => println!("User not found"), 15 }
構造的型付け vs 名目的型付け
構造的(Structural)
同じ構造を持てば互換性あり(ダックタイピング)
TypeScript, Go
名目的(Nominal)
明示的に宣言された関係のみ互換性あり
Java, C#, Rust
1 // TypeScript - 構造的型付け 2 interface Point { 3 x: number; 4 y: number; 5 } 6 7 // 同じ構造を持つオブジェクトは互換 8 const p: Point = { x: 1, y: 2 }; 9 10 // 追加プロパティがあっても構造が満たされればOK 11 const p3d = { x: 1, y: 2, z: 3 }; 12 function printPoint(point: Point) { 13 console.log(point.x, point.y); 14 } 15 printPoint(p3d); // OK
型システムの利点
早期エラー検出
コンパイル時に多くのバグを発見
ドキュメント
型自体がコードの仕様を表す
IDE支援
補完、リファクタリング、ナビゲーション
安全なリファクタリング
型エラーで影響範囲を特定