TypeScriptのoptionalを「何となく」使っていて、? を付ける場所や ?. との関係があいまいなまま書いている、という人は多いはずです。

プロパティに付ける ? と、値を取り出すときの ?. って何が違うの?
? を付けると undefined になるって聞いたけど、どう扱えばいいか分からない。
とりあえず全部 ?. で書いてるけど、これって付けすぎなんじゃ…?

この記事では、型定義に付ける ?(optional property)、関数引数の ?、値を安全に取り出す ?.(optional chaining)、そして !| undefined との線引きまでを地続きに整理します。記号で何となく使っていた状態から、「いつ付け、いつ付けないか」を自分で判断して書けるようになります。

この記事は次のような方におすすめです。

この記事はこんな人におすすめ!
  • ? を見かけて何となく使っているが「いつ付けるべきか」が曖昧な人
  • ?(型定義)と ?.(アクセス)の役割の違いを整理したい人
  • ? を付けると型がどうなるのか、| undefined との違いを知りたい人
  • ?. の付けすぎを避け、迷わずコードを書けるようになりたい人

読み終えるころには、記号と正式名称が頭の中で結びつき、省略可能なプロパティ・引数の書き方から安全なアクセス、乱用を避ける判断まで、ひと続きの知識として使えるようになります。

それでは、順を追って詳しく見ていきましょう!

TypeScriptのoptionalとは|?が登場する3つの場面

TypeScriptで「optional」と呼ばれるものは、ある値や項目を「あってもなくてもよい」と扱うための仕組みの総称です。具体的には次の3つの場面で ? という記号が登場します。

  • プロパティの ?:オブジェクト型で、そのプロパティを省略してよいことを表す
  • 関数引数の ?:その引数を渡さなくても呼び出せることを表す
  • アクセス時の ?.:値が nullundefined でも、エラーにせず安全に取り出す

最小の例で雰囲気をつかんでおきましょう。

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表明)の使いどころと、濫用を避ける判断はこちらで整理しています。
TypeScriptのasとは?型アサーションの危険性と安全な代替TypeScriptのas(型アサーション)を実コードとtscのエラーで解説。書き方・キャストとの違い・なぜ危険かを示し、asを避ける型ガードやsatisfiesまで網羅。エラーを消すだけでなく型安全を守りたい人へ。...

オプショナルプロパティ(?)の書き方|省略可能なプロパティを型で表す

オブジェクト型でプロパティを省略可能にするには、プロパティ名の直後に ? を付けるだけです。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?: numberx: 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つではなく型全体のプロパティをまとめて任意化したい場合は、? を手で付けて回るのではなく、専用のユーティリティ型を使うほうが簡潔です。

なかむぅ
なかむぅ
型全体のプロパティをまとめて省略可能にしたいなら、Partialを使うと一気に書けます。単一プロパティの ? との使い分けはこちらをどうぞ。
TypeScriptのPartial|効かない罠とRequiredの書き分けTypeScriptのPartialで全プロパティを任意化する基本から、ネストに効かない罠・型安全の落とし穴・対になるRequiredとの書き分けまで実コードで解説。更新処理やフォームで迷わず使えるようになります。...
なかむぅ
なかむぅ
undefined になったときの判定方法を、null も含めて体系的に押さえたい方はこちらが参考になります。
TypeScriptのnullが判定できない原因とundefinedとの違いTypeScriptでnullとundefinedの違いに迷い、判定やstrictNullChecksでつまずく人向け。使い分け、== nullでのまとめ判定、??・非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.addressundefined の時点で評価が止まり、その先の .city は実行されないことです。これを「短絡評価」と呼びます。?. が無ければ undefined のプロパティを読もうとして実行時エラーになりますが、?. を挟むことで式全体が静かに undefined を返します。

メソッド呼び出しの u.greet?.() も同様で、greetnull/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 型全体 型のプロパティをまとめて省略可能にする

迷ったときは、次の流れで判断すると選びやすくなります。

TypeScriptのoptional(?)、Partial、undefined、オプショナルチェーン(?.)の使い分けを示す判断フロー図

「省略可は ?、型全体はPartial、安全なアクセスは ?.という3つの軸を押さえておけば、その場の状況に合わせて記号を選び分けられます。

なかむぅ
なかむぅ
optionalは型を安全に扱う手段の一つです。型チェック全体の地図の中での位置づけを俯瞰したい方はこちらをどうぞ。
【TypeScript】型チェックの全手段|typeof・型ガード保存版TypeScriptの型チェックは手段が多く迷いがち。typeof・instanceof・in・ユーザー定義型ガード・null判定・アサーションを実コードと出力付きで整理し、いつどれを使うか判断フローで示します。...

【付録】さらに学びを深めるためのリソース


さらに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を何となくではなく意図を持って書けるようになります。

なかむぅ
なかむぅ
型全体をまとめて任意にしたいときに使うPartialは、? の次に押さえておきたい型です。
TypeScriptのPartial|効かない罠とRequiredの書き分けTypeScriptのPartialで全プロパティを任意化する基本から、ネストに効かない罠・型安全の落とし穴・対になるRequiredとの書き分けまで実コードで解説。更新処理やフォームで迷わず使えるようになります。...
なかむぅ
なかむぅ
nullundefined の判定方法を体系的に学びたい方はこちらをどうぞ。
TypeScriptのnullが判定できない原因とundefinedとの違いTypeScriptでnullとundefinedの違いに迷い、判定やstrictNullChecksでつまずく人向け。使い分け、== nullでのまとめ判定、??・非nullアサーション(!)の安全な書き方を、エラー文とともに整理します。...
なかむぅ
なかむぅ
optionalを含む型チェック全体の地図を俯瞰したい方は、親となるこちらの記事が起点になります。
【TypeScript】型チェックの全手段|typeof・型ガード保存版TypeScriptの型チェックは手段が多く迷いがち。typeof・instanceof・in・ユーザー定義型ガード・null判定・アサーションを実コードと出力付きで整理し、いつどれを使うか判断フローで示します。...

※本記事の本文案はAIを活用して作成していますが、記載している内容およびコードは筆者が実際に調査、検証・実行し、内容の正確性を確認した上で公開しています。