TypeScriptのoptionalとは?’?’と’?.’の使い分けで迷わないようにしよう
TypeScriptのoptionalを「何となく」使っていて、? を付ける場所や ?. との関係があいまいなまま書いている、という人は多いはずです。
? と、値を取り出すときの ?. って何が違うの?
? を付けると undefined になるって聞いたけど、どう扱えばいいか分からない。
?. で書いてるけど、これって付けすぎなんじゃ…?
この記事では、型定義に付ける ?(optional property)、関数引数の ?、値を安全に取り出す ?.(optional chaining)、そして ! や | undefined との線引きまでを地続きに整理します。記号で何となく使っていた状態から、「いつ付け、いつ付けないか」を自分で判断して書けるようになります。
この記事は次のような方におすすめです。
?を見かけて何となく使っているが「いつ付けるべきか」が曖昧な人?(型定義)と?.(アクセス)の役割の違いを整理したい人?を付けると型がどうなるのか、| undefinedとの違いを知りたい人?.の付けすぎを避け、迷わずコードを書けるようになりたい人
読み終えるころには、記号と正式名称が頭の中で結びつき、省略可能なプロパティ・引数の書き方から安全なアクセス、乱用を避ける判断まで、ひと続きの知識として使えるようになります。
それでは、順を追って詳しく見ていきましょう!
- 未経験で後悔したくない
【実体験】未経験からITエンジニアに転職して後悔した話|4社経験してわかった「最初の選択ミス」 - 年収が低くて不安
エンジニア転職体験談|4社で年収250→510万にした全記録
TypeScriptのoptionalとは|?が登場する3つの場面
TypeScriptで「optional」と呼ばれるものは、ある値や項目を「あってもなくてもよい」と扱うための仕組みの総称です。具体的には次の3つの場面で ? という記号が登場します。
- プロパティの
?:オブジェクト型で、そのプロパティを省略してよいことを表す - 関数引数の
?:その引数を渡さなくても呼び出せることを表す - アクセス時の
?.:値がnullやundefinedでも、エラーにせず安全に取り出す
最小の例で雰囲気をつかんでおきましょう。
type User = {
name: string;
age?: number; // age は省略してよい(optional property)
};
const u: User = { name: "Taro" }; // age を書かなくてもOK
console.log(u.age?.toFixed()); // ?. で安全にアクセス → undefined
age には ? が付いているので省略でき、その値へは ?. を使うことで undefined でも落ちずにアクセスできます。?(型定義側)と ?.(アクセス側)は別の機能で、組み合わせて使うのがポイントです。
記号(?・?.)と正式名称の対応表
? と ?.、さらによく一緒に出てくる記号を、正式名称と一言の役割で対応づけておきます。検索では記号でたどり着くことも多いため、ここを索引として押さえておくと迷いにくくなります。
| 記号 | 正式名称 | 一言でいう役割 |
|---|---|---|
?(型定義) |
optional property / optional parameter | プロパティ・引数を省略可能にする |
?. |
optional chaining(オプショナルチェーン) | null/undefinedでも安全に値を取り出す |
?? |
Nullish Coalescing(Null合体演算子) | null/undefinedのときだけ既定値を使う |
! |
Non-null assertion(非null表明) | 「null/undefinedではない」と開発者が表明する |
? は「省略できる」、?. は「無くても安全に取り出す」と覚えておくと、役割の混同が起きにくくなります。表の一番下にある !(Non-null assertion)だけは方向が逆で、「この値は null/undefined ではない」と開発者が表明し、型チェックを黙らせる記号です。
!(非null表明)の使いどころと、濫用を避ける判断はこちらで整理しています。
オプショナルプロパティ(?)の書き方|省略可能なプロパティを型で表す
オブジェクト型でプロパティを省略可能にするには、プロパティ名の直後に ? を付けるだけです。type でも interface でも書き方は同じです。
type Profile = {
id: number;
nickname?: string; // 省略可能
};
interface Config {
port: number;
host?: string; // 省略可能
}
const p: Profile = { id: 1 }; // nickname を省いてもエラーにならない
? を付けると、そのプロパティの型は 指定した型 | undefined として扱われます。つまり省略したときの値は undefined です。
const p: Profile = { id: 1 };
console.log(p.nickname); // 値は undefined
p.nickname.length; // 例:TS18048 'p.nickname' is possibly 'undefined'.(strictNullChecks有効時)
上のように、strictNullChecks が有効な環境では undefined の可能性があるプロパティをそのまま参照するとエラーになります(エラーコードや文言はTypeScriptバージョンにより異なる場合あり)。安全に使うには、後述の ?. や事前の存在チェックを通します。
ここで紛らわしいのが、x?: number と x: number | undefined の違いです。両者は似て見えますが、「キーを省略できるかどうか」が異なります。
| 書き方 | キーの省略 | 値に undefined を明示代入 |
|---|---|---|
x?: number |
できる | 既定では可。exactOptionalPropertyTypes 有効時は不可 |
x: number | undefined |
できない(キーは必須) | 可 |
type A = { x?: number };
type B = { x: number | undefined };
const a: A = {}; // OK:キーごと省略できる
const b1: B = {}; // 例:TS2741 Property 'x' is missing …(キー必須)
const b2: B = { x: undefined }; // OK:値は明示する必要がある
exactOptionalPropertyTypes を有効にすると、x?: number のプロパティに { x: undefined } と明示的に undefined を代入することが弾かれるようになり、「省略」と「undefined代入」がより厳密に区別されます(挙動は設定により変わるため、お使いの構成で確認してください)。
推奨としては、そのプロパティが必須にできるなら ? を安易に付けないのが基本です。? を増やすほど呼び出し側で undefined を考慮する箇所が増え、チェック漏れの温床になります。「本当に省略を許す必要があるか」を一度立ち止まって考えるとよいですよ。
なお、1つ2つではなく型全体のプロパティをまとめて任意化したい場合は、? を手で付けて回るのではなく、専用のユーティリティ型を使うほうが簡潔です。
? との使い分けはこちらをどうぞ。
undefined になったときの判定方法を、null も含めて体系的に押さえたい方はこちらが参考になります。
オプショナル引数(?)の書き方|引数を省略可能にする
関数の引数を省略可能にするには、引数名の直後に ? を付けます。省略して呼び出すと、その引数の値は undefined になります。
function greet(name: string, title?: string) {
// title の型は string | undefined
return title ? `${title} ${name}` : name;
}
greet("Taro"); // "Taro"(title を省略)
greet("Taro", "Dr."); // "Dr. Taro"
似た目的でよく使うのがデフォルト引数です。= 値 を書くと、省略時に undefined ではなく指定した既定値が入ります。
function greet(name: string, title: string = "Mr.") {
return `${title} ${name}`;
}
greet("Taro"); // "Mr. Taro"(省略時は "Mr." が入る)
両者の違いはシンプルで、省略したときに undefined を受け取りたいなら ?、具体的な既定値を入れたいなら = 値 を選びます。
注意点として、オプショナル引数の後ろに必須引数を置くことはできません。省略可能な引数は引数リストの末尾側にまとめる必要があります。
function f(a?: number, b: number) {} // 例:TS1016 A required parameter cannot follow an optional parameter.
function g(a: number, b?: number) {} // OK:必須を先、省略可を後ろに
省略可能なものは後ろへ、と覚えておけば、この制約で詰まることはなくなります。
オプショナルチェーン(?.)の使い方|nullやundefinedでも安全に取り出す
?.(オプショナルチェーン)は、左側の値が null または undefined のとき、その先のアクセスを打ち切って式全体を undefined にする演算子です。途中で値が無くてもエラーで止まらず、安全に取り出せます。使える場面は主に3つあります。
type User = {
name: string;
address?: { city?: string };
greet?: () => string;
tags?: string[];
};
const u: User = { name: "Taro" };
// 1. プロパティ参照
console.log(u.address?.city); // undefined(address が無いので短絡)
// 2. メソッド呼び出し
console.log(u.greet?.()); // undefined(greet が無いので呼ばれない)
// 3. 配列・インデックスアクセス
console.log(u.tags?.[0]); // undefined(tags が無いので短絡)
ポイントは、u.address が undefined の時点で評価が止まり、その先の .city は実行されないことです。これを「短絡評価」と呼びます。?. が無ければ undefined のプロパティを読もうとして実行時エラーになりますが、?. を挟むことで式全体が静かに undefined を返します。
メソッド呼び出しの u.greet?.() も同様で、greet が null/undefined なら呼び出し自体をスキップします。「関数が存在すれば呼ぶ」を1行で書ける、便利な書き方です。
推奨としては、「本当に値が無い可能性がある場所」にだけ ?. を使うこと。常に存在すると分かっている値にまで付けると、かえってコードの意図がぼやけます。
??(Null合体演算子)と組み合わせて初期値を入れる
?. の結果が undefined になったとき、そのまま使うのではなく既定値を入れたいことはよくあります。そこで ??(Null合体演算子)と組み合わせます。a?.b ?? 既定値 と書くと、左側が null/undefined のときだけ既定値が使われます。
const u: User = { name: "Taro" };
const city = u.address?.city ?? "未設定";
console.log(city); // "未設定"(address が無いので既定値)
ここで || ではなく ?? を使うのが重要なポイントです。|| は 0 や空文字 "" も「偽」とみなして既定値に置き換えてしまいますが、?? は null/undefined のときだけ既定値を使うため、0 や "" をそのまま活かせます。
?.の付けすぎに注意|不要なoptional chainを増やさない
?. は便利ですが、本来 null/undefined にならない値にまで付けると、かえって問題を招きます。理由は2つあります。
- バグを隠す:本来あるはずの値が無いとき、
?.が静かにundefinedを返すため、異常に気づきにくくなる - 型の意図がぼやける:「この値は無いこともある」という誤ったメッセージをコードに残してしまう
type Order = { id: number; total: number };
function format(o: Order) {
// o.total は必須(undefined にならない)のに ?. を付けている
return `合計: ${o.total?.toLocaleString()}`; // 不要な ?. でバグを隠す
}
上の o.total は型の上で必ず存在するため、?. は不要です。むしろ ?. を付けることで「total が無いかもしれない」という誤解を残し、本来検知すべき不整合を握りつぶしてしまいます。?. は「型が ?、| undefined、| null などで、実際に null/undefined の可能性がある箇所」にだけ使うのが原則です。
?と?.を一枚で整理|使い分けと判断フロー
ここまでの記号の役割を一枚に並べて整理します。「型定義で省略可を示す ?」「アクセス時に安全に取り出す ?.」、そして切り替え先の | undefined・Partial まで、それぞれの守備範囲は次のとおりです。
| 書き方 | 使う場所 | 役割 |
|---|---|---|
?(プロパティ) |
オブジェクト型 | そのプロパティを省略可能にする |
?(引数) |
関数の引数 | その引数を省略可能にする |
?. |
値へのアクセス | null/undefinedでも安全に取り出す |
| undefined |
型注釈 | キーは必須のまま、値にundefinedを許す |
| Partial | 型全体 | 型のプロパティをまとめて省略可能にする |
迷ったときは、次の流れで判断すると選びやすくなります。
「省略可は ?、型全体はPartial、安全なアクセスは ?.」という3つの軸を押さえておけば、その場の状況に合わせて記号を選び分けられます。
【付録】さらに学びを深めるためのリソース
さらにTypescriptの学習を進めたい方のために、いくつかのリソースを紹介します。
これらのリソースを活用することで、TypeScriptの型システムについてより深い知識を得ることができるでしょう。
おすすめの書籍
ゼロからわかる TypeScript入門
技術評論社から出版されている「ゼロからわかる TypeScript入門」は、プログラミング初心者や本職プログラマーではない方を主な対象にした入門書です。
変数・条件分岐・ループといった基本から、クラスやインターフェース、モジュールまで段階的に学べる構成になっています。最終章ではWeb APIとJSONを使った非同期Webアプリの作成も体験できるので、「実際に動くものを作る」ところまで到達できます。
プロを目指す人のためのTypeScript入門
技術評論社の「プロを目指す人のためのTypeScript入門 安全なコードの書き方から高度な型の使い方まで」、通称 ブルーベリー本 です。
JavaScriptの仕様とTypeScript独自の機能を両方押さえつつ、リテラル型・ユニオン型・keyof型・ジェネリクスなど、高度な型表現まで踏み込んで解説しています。TypeScriptの型システムの表現力を本格的に学べる一冊です。
オンラインで参照できる公式ドキュメント
TypeScript公式ハンドブック
https://www.typescriptlang.org/docs/
TypeScriptの公式ドキュメントです。
intersection型を含む、すべての型システムの機能について詳細な説明があります。
TypeScript Deep Dive
https://basarat.gitbook.io/typescript/
TypeScriptの深い部分まで掘り下げて解説しているオンラインブックです。
無料で読むことができ、intersection型についても詳しく説明されています。
TypeScriptの学習は終わりがありません。
新しい機能が常に追加され、より良い書き方が発見されています。
継続的に学習を続けることで、より良いTypeScriptプログラマーになれるはずです。
まとめ – ?と?.の役割を押さえて迷わず使い分ける
この記事では、TypeScriptのoptionalにまつわる ? と ?. の役割と使い分けを整理しました。
?(プロパティ・引数):省略可能にする。省略時の値はundefined?.(optional chaining):null/undefinedでも安全に取り出し、無ければ式全体がundefined??(Null合体):?.の結果が null/undefined のときだけ既定値を入れる- 判断軸:単一プロパティは
?、型全体はPartial、アクセス時の安全確保は?.
記号と正式名称、そして「いつ付け、いつ付けないか」が結びつけば、optionalを何となくではなく意図を持って書けるようになります。
? の次に押さえておきたい型です。
null・undefined の判定方法を体系的に学びたい方はこちらをどうぞ。
※本記事の本文案はAIを活用して作成していますが、記載している内容およびコードは筆者が実際に調査、検証・実行し、内容の正確性を確認した上で公開しています。






