【実務・中級編】 JSDocにおける省略可能引数の定義 – JavaScript実践ガイド

フロントエンド開発の現場で、TypeScriptの導入が進んでいるとはいえ、未だにレガシーなJSコードベースや、あえてビルドステップを挟まない軽量なスクリプト、あるいはJSDocベースの型安全性(TypeScriptのJSDocモード)を好むプロジェクトに遭遇することは少なくない。

特に、ライブラリや汎用的なユーティリティ関数を設計する際、「この引数は渡さなくてもデフォルト値で動いてほしいけど、どうドキュメント化し、どう型を効かせればいいんだ?」と悩んだ経験はないだろうか。

今回は、JSDocにおける省略可能(オプショナル)引数の定義方法について、JavaScriptのランタイムの挙動や、エディタ(VSCode等)の補完機能が裏側でどう動いているのかという実務に直結する知見を交えて解説しよう。

—

1. JSDocにおける省略可能引数の基本構文

JSDocで引数を「省略可能」にするのは極めてシンプルだ。
対象となる引数名を 角括弧 `[]` で囲むだけでいい。

/

  • ユーザーのプロフィールを表示する関数
  • @param {string} username – ユーザー名(必須)
  • @param {string} [role] – ユーザーのロール(省略可能)

/
function displayProfile(username, role) {
// 省略された場合のフォールバック処理
const userRole = role !== undefined ? role : ‘guest’;
console.log(`${username} さん (権限: ${userRole})`);
}

この `@param {string} [role]` という書き方を見て、「なんだ、ただ括弧で囲むだけか」とスルーしないでほしい。この角括弧が、IDEのIntelliSenseに対して「この引数はundefinedになり得るし、呼び出し時に渡さなくても怒らないでね」という強力なシグナルを送っているのだ。

さらに踏み込む:デフォルト値の明記

実務では、単に省略可能とするだけでなく、「省略されたらこの値を使う」というデフォルト値をJSDoc上やコード内で定義することが多い。JSDocでは以下のように書くことで、デフォルト値をもドキュメント化できる。

/

  • APIリクエストを実行する
  • @param {string} url – リクエスト先URL
  • @param {string} [method=’GET’] – HTTPメソッド(省略時はGET)

/
function apiRequest(url, method = ‘GET’) {
// 実装…
}

この `= ‘GET’` の記述方法により、VSCodeなどのエディタは「この引数はstring型であり、省略時は自動的に文字列の’GET’が補完される」と完璧に理解する。

—

2. JavaScriptの裏側:引数の省略と `undefined` の正体

ここで少し視野を広げて、ブラウザのJavaScriptエンジン(V8など)が裏側でどう動いているのかを覗いてみよう。

JavaScriptにおいて、関数に定義された引数(仮引数)と、実際に呼び出し時に渡された値(実引数)の数は一致している必要はない。
例えば、次のような関数があったとする。

function sum(a, b) {
console.log(arguments);
return a + b;
}

sum(10); // b は渡されていない

このとき、エンジン内部では何が起きているのか?
渡されなかった `b` には、自動的にプリミティブ型の `undefined` がバインドされる。

ここで注意深い中級エンジニアなら気づくだろう。「あれ、`null` とはどう違うんだっけ?」と。
JavaScriptにおける「値が存在しない、または未定義である」状態を表す場合、明示的に開発者が代入する `null` と、エンジンや言語仕様が自動的に割り当てる `undefined` は厳密に区別されるべきだ。

JSDocで `[role]` と定義した場合、それは「この引数は `undefined` になる可能性がある(あるいは省略できる)」ことを意味する。もし、呼び出し元が意図的に `null` を渡してきた場合、型チェックを厳密に行う環境では警告の対象になることもあるため、実務では以下のようなガード句を挟むのがプロの技だ。

/

  • @param {string} [theme=’light’] – テーマカラー

/
function setTheme(theme) {
// nullish coalescing (??) を使って、undefined または null の場合にデフォルト値を適用
const currentTheme = theme ?? ‘light’;
document.body.className = currentTheme;
}

`||` 演算子ではなく `??`(Nullish coalescing)を使うのがポイントだ。空文字 `””` などを有効な値として扱いたい場合、`||` だと意図せずデフォルト値にフォールバックしてしまうバグを生むからだ。

—

3. 現場で使える!実践的なサンプルコード

それでは、実務のフロントエンド開発でよく遭遇する、オプション引数とオブジェクト構造メンテナスを組み合わせた実践的なパターンを見てみよう。

近年のモダンなJS/TS開発では、引数が3つ以上になる場合、位置引数ではなく「オブジェクトの分割代入(Options Object Pattern)」を使うのがデファクトスタンダードだ。その場合のJSDocの書き方もあわせてマスターしておこう。

/

  • 汎用的なモーダルを開く関数
  • @param {Object} options – モーダルの設定オブジェクト
  • @param {string} options.title – モーダルのタイトル(必須)
  • @param {string} [options.body=”] – モーダルの本文(省略可能)
  • @param {boolean} [options.isClosable=true] – 閉じるボタンを表示するかどうか
  • @param {Function} [options.onClose] – モーダルが閉じた時のコールバック
  • @returns {HTMLElement} 生成されたモーダルのDOM要素

/
function createModal({ title, body = ”, isClosable = true, onClose }) {
const modal = document.createElement(‘div’);
modal.className = ‘custom-modal’;

// タイトルの構築
const h2 = document.createElement(‘h2’);
h2.textContent = title;
modal.appendChild(h2);

// 本文の構築(省略時は空文字)
if (body) {
const p = document.createElement(‘p’);
p.textContent = body;
modal.appendChild(p);
}

// 閉じるボタンの制御
if (isClosable) {
const closeBtn = document.createElement(‘button’);
closeBtn.textContent = ‘閉じる’;
closeBtn.addEventListener(‘click’, () => {
modal.remove();
// onCloseが関数として存在する場合のみ実行(オプショナルチェイニング)
if (typeof onClose === ‘function’) {
onClose();
}
});
modal.appendChild(closeBtn);
}

return modal;
}

// — 実際の利用シーン —

// 1. 最小限の引数で呼ぶ
const simpleModal = createModal({
title: ‘お知らせ’
});

// 2. すべてのオプションを指定して呼ぶ
const complexModal = createModal({
title: ‘データ削除の確認’,
body: ‘本当にこのデータを削除してもよろしいですか?’,
isClosable: true,
onClose: () => {
console.log(‘モーダルが閉じられました。画面を再読み込みします。’);
// location.reload();
}
});

このコードのアーキテクチャ的な旨味

1. オブジェクトのプロパティ単位でのJSDoc: `options.body` のようにドットつなぎで書くことで、オブジェクトの特定のキーだけに省略可能(`[]`)とデフォルト値を指定できる。
2. 安全なコールバック実行: `onClose` のように「渡されてもいなくてもいい関数」は、JSDocで `@param {Function} [options.onClose]` と定義し、実行時にも `typeof onClose === ‘function’` でガードするか、オプショナルチェイニング(`onClose?.()`)を使うことで、`TypeError: onClose is not a function` というフロントエンド開発でありがちな恐怖のバグを完全防衛できる。

—

4. シニアからのアドバイス:型コメントを制する者はコードを制す

「たかがコメント、されどJSDoc」だ。
JSDocの省略可能引数(`[]`)を正しく使いこなせるようになると、TypeScriptへ完全移行していないプロジェクトであっても、IDEのコード補完や静的解析の恩恵を最大限に受けることができる。

チームメンバーが新しく君の書いた関数を使うとき、わざわざ関数の実装の中身を覗きに行かなくても、エディタのポップアップ(ホバー)だけで「あ、この引数はオプショナルなんだな」「省略したらこの値になるんだな」と一目で理解できる。この開発体験の差が、チーム全体の開発スピードとコードの堅牢性に直結するのだ。

今日から君が書くユーティリティ関数やコンポーネントのラッパーには、ぜひ正確な角括弧 `[]` を仕込んでみてほしい。コードの美しさが一段階引き上がるはずだ。

コメント

タイトルとURLをコピーしました