Null 安全性
null 参照エラーを型システムで防止し、null の可能性がある値を明示的に扱うプログラミング言語の機能
Null 安全性とは
Null 安全性 (Null Safety) は、null 参照エラー (NullPointerException, TypeError: Cannot read properties of null) を型システムで防止するプログラミング言語の機能である。Tony Hoare は 2009 年の講演で、自身が ALGOL W に null 参照を導入したことを「10 億ドルの過ち」と振り返っている。null を許す言語では、値が無い場合の扱い漏れがコンパイル時に検出されず、実行時になって初めて例外として露見する。
TypeScript の strictNullChecks
TypeScript の strictNullChecks を有効にすると、null と undefined はそれぞれ独立した型として扱われ、具体的な値が期待される場所へ渡すと型エラーになる。無効のときは両者が言語側で事実上無視されるため、型チェックを通ったコードが実行時に落ちる。
// strictNullChecks: true
function getUser(id: string): User | null {
return db.find(id) ?? null;
}
const user = getUser('123');
// user.name; // ❌ コンパイルエラー: Object is possibly 'null'
if (user) {
user.name; // ✅ OK: null チェック後は User 型に絞り込まれる
}
// Optional Chaining
const name = user?.name; // string | undefined
const city = user?.address?.city; // string | undefined
// Nullish Coalescing
const displayName = user?.name ?? 'Anonymous'; // string
言語ごとの Null 安全性
同じ「null 安全」でも、言語レベルで null を排除する設計と、既存の null に型で注意書きを付ける設計に分かれる。
| 言語 | 仕組み | null の扱い |
|---|---|---|
| TypeScript | strictNullChecks | T | null で明示 |
| Rust | Option<T> | null が存在しない |
| Kotlin | String? (Nullable 型) | ? で明示 |
| Swift | String? (Optional) | ? で明示 |
| Java | Optional<T> | ライブラリレベル (言語レベルではない) |
Rust は言語レベルで null が存在せず、Option<T> (Some(value) or None) で値の有無を表現する。パターンマッチで網羅的に処理するため、値が無い場合の分岐を書き忘れるとコンパイルが通らない。
ただし unwrap や expect で中身を取り出せば、None のときに panic する。網羅性の検査を呼び出し側から放棄できるという点では、後述する TypeScript の Non-null Assertion (!) と同じ性質の抜け道が残っている。
TypeScript での実践パターン
Non-null Assertion の回避
// ❌ Non-null Assertion (!): null チェックをスキップ (危険)
const user = getUser('123')!; // null なら実行時エラー
// ✅ 明示的な null チェック
const user = getUser('123');
if (!user) throw new Error('User not found');
// この行以降、user は User 型に絞り込まれる
Optional Chaining と Nullish Coalescing
// ❌ 冗長な null チェック
const city = user && user.address && user.address.city ? user.address.city : 'Unknown';
// ✅ Optional Chaining + Nullish Coalescing
const city = user?.address?.city ?? 'Unknown';
関数の戻り値で null を避ける
// ❌ null を返す: 呼び出し側が null チェックを忘れるリスク
function findUser(id: string): User | null { /* ... */ }
// ✅ 例外をスロー: 見つからない場合は明示的にエラー
function getUserOrThrow(id: string): User {
const user = db.find(id);
if (!user) throw new NotFoundError(`User ${id} not found`);
return user;
}
strictNullChecks を有効にする
既存プロジェクトへ導入するときは、strict を一括で有効にするのが最も手数が少ない。
{
"compilerOptions": {
"strict": true // strictNullChecks を含む全 strict オプションを有効化
}
}
既存プロジェクトで有効化すると大量のエラーが出る。ファイル単位で移行したい場合は、まず strictNullChecks だけを有効にし、エラーが多いファイルから ! を使わずに絞り込みへ置き換えていく。エラーの総数はそのままバグの候補数ではないが、null 由来の例外を実行時からコンパイル時へ前倒しできる。
現場での応用を知るには関連書籍も役立つ。
この記事は役に立ちましたか?