TypeScriptの「デフォルト引数」と「オプショナル引数」を制する:型システムの深淵へ
こんにちは。TypeScriptのコードベースを日々深く掘り下げていると、一見シンプルに見える関数の型定義の中に、言語設計の「哲学」が詰まっていることに気づかされます。
今回は、TypeScriptを学び始めた方が必ず一度は立ち止まる「デフォルト引数がある場合の型推論」と「オプショナル引数との共存」について深掘りしていきましょう。ここをマスターすれば、TypeScriptの型システムが「どうやって安全性を担保しているのか」という本質が見えてきますよ。
—
1. 基本のキ:オプショナル引数とデフォルト引数
まずは、それぞれの書き方をおさらいしましょう。
オプショナル引数 (`?`)
「この引数は渡してもいいし、渡さなくてもいい(その場合は `undefined` になる)」という宣言です。
function greet(name?: string) {
// name は string | undefined になる
console.log(`Hello, ${name ?? “Guest”}`);
}
デフォルト引数 (`=`)
「渡されなかった場合は、この値を代入しておくよ」という親切な仕組みです。
function greet(name: string = “Guest”) {
// name は string として推論される(undefinedにはなり得ない!)
console.log(`Hello, ${name}`);
}
—
2. なぜ「共存」させるとエラーになるのか?
ここでよくあるミスが、この2つを組み合わせてしまうことです。
// ❌ コンパイルエラー!
function createUser(name?: string = “Anonymous”) {
// …
}
なぜエラーになるのでしょうか? TypeScriptのコンパイラはこう考えています。
「`?` は『引数が省略されたら `undefined` を許容する』という宣言であり、`= “Anonymous”` は『引数が省略されたら `Anonymous` を代入する』という宣言だ。どっちを優先すればいいんだ?」
型システム的に言えば、「オプショナル(undefinedになり得る)」という性質と、「デフォルト値(初期値を持つのでundefinedではない)」という性質は、論理的に矛盾するのです。
解決策:どちらか一方を選ぶ
- デフォルト値を優先したい場合: `?` を外す。
- 明示的に `undefined` を渡したい場合: デフォルト引数を使わず、関数内で `??` 演算子を使って処理する。
—
3. 型推論の「裏側」を覗く
次に、デフォルト引数がある場合の型推論を見てみましょう。実は、デフォルト値を設定すると、その引数の型は「デフォルト値の型」から自動的に推論されます。
// 型を明示しなくても、valueは number と推論される
function increment(value = 0) {
return value + 1;
}
// 呼び出し側も安全にチェックされる
increment(10); // OK
increment(); // OK (デフォルト値が使われる)
// increment(“1”); // ❌ エラー! number型を期待しているのにstringが来た
ここがTypeScriptの賢いところです。わざわざ `value: number = 0` と書かなくても、`0` という値から「これは数値だ」と察知してくれる。この「型推論の最小化」こそが、TypeScriptを書きやすく、かつ堅牢にしている理由です。
—
4. 実践的なテクニック:引数の順序が運命を変える
現場でコードを書く際、一つだけ守ってほしい鉄則があります。
「デフォルト引数を持つ引数は、必ず末尾に配置する」
もし、デフォルト引数を持つ引数を関数の先頭に置くとどうなるでしょうか?
function configure(width: number = 100, height: number) {
// …
}
configure(200); // 呼び出し側で height はどう渡せばいい?
これでは、`200` が `width` なのか `height` なのか、読み手もコンパイラも混乱します。TypeScriptでは、デフォルト引数を持つ引数の後に、必須引数を配置することは推奨されません。
正しい作法:
function configure(height: number, width: number = 100) {
// 必須のものは左に、デフォルト値を持つものは右に。
// これがAPI設計の黄金律です。
}
—
まとめ:TypeScriptをマスターするために
今回のポイントを整理します。
1. `?` と `= 値` は同時に使わない。 矛盾するシグネチャを避けるのが型安全の第一歩です。
2. 型推論を信じる。 `value = 0` と書けば、その引数は自動的に `number` です。過剰な型注釈は、時に可読性を下げます。
3. 引数の順序は「必須 → デフォルト」の順で。 これを守るだけで、あなたの書くコードは驚くほど美しく、使いやすくなります。
TypeScriptの型システムは、あなたのコードの「意図」をコンパイラに伝えるための翻訳機です。デフォルト値という小さな仕組み一つとっても、それがどう評価され、どう呼び出し元を縛るのか。その感覚を研ぎ澄ませていけば、あなたはもうTypeScriptを掌握しつつあります。
これからもその好奇心を忘れずに、型という名の「地図」を持って、コードの荒野を冒険していってくださいね!