Option / Result 型
null や例外の代わりに、値の有無やエラーを型で表現する関数型プログラミングのパターン
型システム品質
Option / Result 型とは
Option 型 (Maybe 型) と Result 型は、null や例外の代わりに、値の有無やエラーを型で表現するパターンである。Rust、Haskell、Scala で標準的に使われ、TypeScript でも Discriminated Union で実装できる。
null の問題
// ❌ null を返す: 呼び出し側が null チェックを忘れるとランタイムエラー
function findUser(id: string): User | null {
return db.get(id); // null かもしれない
}
const user = findUser('123');
console.log(user.name); // 💥 TypeError: Cannot read property 'name' of null
TypeScript での Option 型
type Option<T> = { kind: 'some'; value: T } | { kind: 'none' };
const some = <T>(value: T): Option<T> => ({ kind: 'some', value });
const none: Option<never> = { kind: 'none' };
function findUser(id: string): Option<User> {
const user = db.get(id);
return user ? some(user) : none;
}
const result = findUser('123');
if (result.kind === 'some') {
console.log(result.value.name); // ✅ 型安全
}
TypeScript での Result 型
type Result<T, E> = { ok: true; value: T } | { ok: false; error: E };
function parseJson<T>(raw: string): Result<T, string> {
try {
return { ok: true, value: JSON.parse(raw) };
} catch (e) {
return { ok: false, error: `Parse error: ${e}` };
}
}
const result = parseJson<User>('{"name":"Alice"}');
if (result.ok) {
console.log(result.value.name); // ✅ 型安全
} else {
console.error(result.error); // ✅ エラーも型安全
}
Rust の Option / Result
// Option<T>: Some(T) or None
fn find_user(id: &str) -> Option<User> {
db.get(id) // None を返す可能性がある
}
// Result<T, E>: Ok(T) or Err(E)
fn parse_config(path: &str) -> Result<Config, io::Error> {
let content = fs::read_to_string(path)?; // ? で早期リターン
Ok(toml::from_str(&content)?)
}
try-catch との比較
| 観点 | try-catch | Result 型 |
|---|---|---|
| エラーの型 | any (TypeScript) | 明示的な型 |
| 網羅性チェック | なし | コンパイラが検証 |
| エラーの伝播 | throw | ? 演算子 (Rust) |
| パフォーマンス | スタックの巻き戻し | 通常の戻り値 |
neverthrow (TypeScript ライブラリ)
import { ok, err, Result } from 'neverthrow';
function divide(a: number, b: number): Result<number, string> {
if (b === 0) return err('Division by zero');
return ok(a / b);
}
divide(10, 0)
.map(v => v * 2)
.mapErr(e => `Error: ${e}`);
より深く学ぶには関連書籍が役立つ。