TypeScript PR

【TypeScript】はてな2つ(??)演算子の使い方と||との違いを解説

記事内に商品プロモーションを含む場合があります

こんにちは!

TypeScriptでコーディングをしていると、「??」という謎の記号に遭遇することがありませんか?

この「??」って何だろう?見たことない記号だな…
|| 演算子との違いがよくわからない…
どんな場面で使うものなの?

TypeScriptやJavaScriptでの開発において、このような疑問をお持ちではないでしょうか。

この記事では、TypeScriptの「はてな2つ」こと「??演算子(Null合体演算子)」について、基本概念から具体的な使い方、従来の||演算子との違いまでを詳しく解説します。

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

この記事はこんな人におすすめ!
  • TypeScriptの??演算子について知りたい方
  • nullundefined の安全な処理方法を学びたい方
  • || 演算子との使い分けを理解したい開発者
  • より安全なTypeScriptコードを書きたい方
  • ES2020の新機能に興味がある方

この記事を読めば、??演算子の仕組みが理解でき、実際のプロジェクトですぐに活用できるスキルが身につきます。TypeScriptでの安全なnull/undefined処理を取り入れて、より堅牢なコードを書けるようになりましょう。

nullundefined のエラーを減らしたい方」「最新のTypeScript機能を活用したい方」は、ぜひ参考にしてください。

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

??演算子とは何か

??演算子は、正式には「Null合体演算子(Nullish Coalescing Operator)」と呼ばれます。この演算子は、左辺の値がnullまたはundefinedの場合に右辺の値を返し、それ以外の場合は左辺の値をそのまま返すという機能を持っています。

??演算子の基本的な特徴は以下の通りです。

  • nullundefinedのみを無効な値として判定する
  • 他のfalsy値(0、”、false等)は有効な値として扱う
  • デフォルト値の設定に便利
  • ES2020で標準化された比較的新しい機能

この演算子は、ECMAScript 2020で正式に導入され、TypeScript 3.7以降で使用可能になりました。現在は主要なブラウザとNode.js v14以降でサポートされています。

??演算子と||演算子の違い

TypeScriptでデフォルト値を設定する際、従来は||演算子がよく使われていました。しかし、??演算子と||演算子には重要な違いがあります。

演算子 判定する値 動作
?? nullundefinedのみ 左辺がnullまたはundefinedの場合のみ右辺を返す
|| すべてのfalsy値 左辺がfalsy(false0''nullundefined等)の場合に右辺を返す

この違いが重要な理由を具体例で見てみましょう。

// 数値の例
const score = 0;
console.log(score || 100);  // 100(0はfalsyなので右辺が返される)
console.log(score ?? 100);  // 0(0はnullでもundefinedでもないので左辺が返される)

// 文字列の例
const message = '';
console.log(message || 'デフォルト');  // 'デフォルト'(空文字はfalsyなので右辺が返される)
console.log(message ?? 'デフォルト');  // ''(空文字はnullでもundefinedでもないので左辺が返される)

// ブール値の例
const flag = false;
console.log(flag || true);   // true(falseはfalsyなので右辺が返される)
console.log(flag ?? true);   // false(falseはnullでもundefinedでもないので左辺が返される)

このように、??演算子はnullundefined以外の値を「有効な値」として扱うため、より厳密な判定ができます。

??演算子の基本的な使い方

??演算子の基本的な構文は非常にシンプルです。

左辺 ?? 右辺

具体的な使用例を見てみましょう。

// 基本的な使用例
let userName: string | null = null;
let displayName = userName ?? 'ゲスト';
console.log(displayName); // 'ゲスト'

userName = '山田太郎';
displayName = userName ?? 'ゲスト';
console.log(displayName); // '山田太郎'

// 関数の引数でのデフォルト値設定
function greet(name?: string) {
  const actualName = name ?? '名無し';
  return `こんにちは、${actualName}さん!`;
}

console.log(greet());        // 'こんにちは、名無しさん!'
console.log(greet('佐藤'));  // 'こんにちは、佐藤さん!'

// オブジェクトのプロパティでの使用
interface User {
  id: number;
  name: string;
  email?: string;
}

const user: User = {
  id: 1,
  name: '田中',
  // email は省略
};

const userEmail = user.email ?? 'メールアドレス未設定';
console.log(userEmail); // 'メールアドレス未設定'

実際の開発での活用例

??演算子は、実際の開発において様々な場面で活用できます。

APIレスポンスの処理

APIから取得したデータでオプショナルなプロパティを安全に処理できます。

interface ApiResponse {
  id: number;
  name: string;
  description?: string;
  imageUrl?: string;
  tags?: string[];
}

function processApiData(data: ApiResponse) {
  return {
    id: data.id,
    name: data.name,
    description: data.description ?? '説明がありません',
    imageUrl: data.imageUrl ?? '/images/default.png',
    tagCount: (data.tags ?? []).length
  };
}

// 使用例
const apiData: ApiResponse = {
  id: 1,
  name: '商品A'
  // description, imageUrl, tags は未定義
};

const processed = processApiData(apiData);
console.log(processed);
// {
//   id: 1,
//   name: '商品A',
//   description: '説明がありません',
//   imageUrl: '/images/default.png',
//   tagCount: 0
// }

設定オブジェクトのデフォルト値設定

アプリケーションの設定で、未指定の項目にデフォルト値を適用する場合にも便利です。

interface AppConfig {
  theme?: 'light' | 'dark';
  language?: 'ja' | 'en';
  pageSize?: number;
  autoSave?: boolean;
}

function createConfig(userConfig: AppConfig = {}): Required<AppConfig> {
  return {
    theme: userConfig.theme ?? 'light',
    language: userConfig.language ?? 'ja',
    pageSize: userConfig.pageSize ?? 20,
    autoSave: userConfig.autoSave ?? true
  };
}

// 使用例
const config1 = createConfig();
console.log(config1);
// { theme: 'light', language: 'ja', pageSize: 20, autoSave: true }

const config2 = createConfig({ theme: 'dark', pageSize: 50 });
console.log(config2);
// { theme: 'dark', language: 'ja', pageSize: 50, autoSave: true }

環境変数の処理

Node.jsアプリケーションで環境変数を扱う際にも??演算子が活躍します。

// 環境変数の安全な取得
const port = process.env.PORT ?? '3000';
const dbUrl = process.env.DATABASE_URL ?? 'mongodb://localhost:27017/myapp';
const logLevel = process.env.LOG_LEVEL ?? 'info';

console.log(`サーバーはポート${port}で起動します`);
console.log(`データベースURL: ${dbUrl}`);
console.log(`ログレベル: ${logLevel}`);

??演算子とオプショナルチェーン(?.)の組み合わせ

??演算子は、オプショナルチェーン演算子(?.)と組み合わせて使用することで、ランタイムエラーを防ぎながら適切なデフォルト値を設定できるため、より安全なコードを書くことができます。オプショナルチェーンでnull/undefinedのプロパティアクセスエラーを防ぎ、??演算子でundefinedの場合の代替値を提供するという二重の安全策が実現できます。

interface Address {
  prefecture: string;
  city: string;
  street?: string;
}

interface User {
  id: number;
  name: string;
  address?: Address;
}

const user: User = {
  id: 1,
  name: '鈴木',
  // address は未定義
};

// オプショナルチェーンと??演算子の組み合わせ
const prefecture = user.address?.prefecture ?? '都道府県不明';
const city = user.address?.city ?? '市区町村不明';
const street = user.address?.street ?? '番地不明';

console.log(`住所: ${prefecture} ${city} ${street}`);
// '住所: 都道府県不明 市区町村不明 番地不明'

// より深いネストの場合
interface Company {
  name: string;
  address?: Address;
}

interface Employee {
  name: string;
  company?: Company;
}

const employee: Employee = {
  name: '高橋'
  // company は未定義
};

const companyCity = employee.company?.address?.city ?? '勤務地不明';
console.log(`勤務地: ${companyCity}`); // '勤務地: 勤務地不明'

パフォーマンスと注意点

??演算子を使用する際に知っておくべきパフォーマンスと注意点があります。

短絡評価

??演算子は短絡評価を行います。つまり、左辺がnullでもundefinedでもない場合、右辺の式は評価されません。

function expensiveCalculation() {
  console.log('重い計算が実行されました');
  return 100;
}

const value1 = 42;
const result1 = value1 ?? expensiveCalculation();
// 'expensiveCalculation'は呼び出されず、ログも出力されない

const value2 = null;
const result2 = value2 ?? expensiveCalculation();
// 'expensiveCalculation'が呼び出され、ログが出力される

演算子の優先順位

??演算子は演算子の優先順位が比較的低いため、複雑な式では括弧を使って明示的に優先順位を指定することが重要です。

// 推奨されない書き方
const result1 = a && b ?? c; // エラーになる可能性がある

// 推奨される書き方
const result2 = (a && b) ?? c;
const result3 = a && (b ?? c);

&&演算子や||演算子との直接結合の制限

??演算子は&&||演算子と直接結合することができません。括弧を使って明示的にグループ化する必要があります。

// これはSyntaxErrorになる
// const result = a || b ?? c;

// 正しい書き方
const result1 = (a || b) ?? c;
const result2 = a || (b ?? c);

??=演算子(Null合体代入演算子)

TypeScript 4.0以降では、??演算子の派生版として「??=」(Null合体代入演算子)も使用できます。

// ??= 演算子の使用例
let config: { name?: string; theme?: string } = {};

// 以下の2行は同じ意味
config.name = config.name ?? 'デフォルト名';
config.name ??= 'デフォルト名';

// オブジェクトの初期化に便利
function initializeUser(user: Partial<User>) {
  user.name ??= '名無し';
  user.email ??= 'no-email@example.com';
  user.role ??= 'guest';

  return user as User;
}

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


さらにTypescriptの学習を進めたい方のために、いくつかのリソースを紹介します。
これらのリソースを活用することで、TypeScriptの型システムについてより深い知識を得ることができるでしょう。

おすすめの書籍


プロを目指す人のためのTypeScript入門


プロ開発者への近道!基礎から応用まで幅広くカバー

1一番のおすすめは「プロを目指す人のためのTypeScript入門」です。
この本は、TypeScriptの基礎から高度な使い方まで幅広く解説しています。

初心者でも理解しやすい説明から始まり、徐々に難易度を上げていく構成が特徴。
プログラミング経験者なら、さらに深い理解が得られるでしょう。

実際の開発現場で使えるテクニックも豊富に紹介されているのがポイント。
型の使い方や設計パターンなど、実践的な内容が満載です。

プロの開発者を目指す人はもちろん、TypeScriptをしっかり学びたい人におすすめの一冊。
基礎固めから応用力の向上まで、幅広いニーズに応えてくれます。

現場で使えるTypeScript 詳解実践ガイド


実践的スキルを身につけたい人必見!現場のノウハウが詰まった一冊

次におすすめは「現場で使えるTypeScript 詳解実践ガイド」がランクイン。
この本の特徴は、実際の開発現場で役立つ知識が詰まっていること。

TypeScriptの基本的な文法から始まり、実際のプロジェクトでどう活用するかまで丁寧に解説しています。
エラー対処法や性能改善のコツなど、現場ならではの知恵も満載。

特に、大規模なプロジェクトでTypeScriptを使う際のベストプラクティスが学べるのが魅力。
コードの保守性や再利用性を高める方法も詳しく紹介されています。

すでにJavaScriptの経験がある人や、実務でTypeScriptを使いたい人におすすめ。
この本を読めば、現場で即戦力として活躍できる力が身につくはずです。

書籍に関してはこちらの記事も参考にしてくださいね!




オンラインで参照できる公式ドキュメント


TypeScript公式ハンドブック


https://www.typescriptlang.org/docs/
TypeScriptの公式ドキュメントです。
intersection型を含む、すべての型システムの機能について詳細な説明があります。

TypeScript Deep Dive


https://basarat.gitbook.io/typescript/
TypeScriptの深い部分まで掘り下げて解説しているオンラインブックです。
無料で読むことができ、intersection型についても詳しく説明されています。

TypeScriptの学習は終わりがありません。
新しい機能が常に追加され、より良い書き方が発見されています。
継続的に学習を続けることで、より良いTypeScriptプログラマーになれるはずです。

キャリア形成/給与還元
ひとつひとつ真摯に向き合う企業
ONE_WEDGE社員募集

株式会社 ONE WEDGEでは、新たな仲間を募集しています!

私たちと一緒に、革新的で充実したキャリアを築きませんか?
当社は、従業員が仕事と私生活のバランスを大切にできるよう、充実した福利厚生を整えています。

  • 完全週休2日制(土日休み)で、祝日や夏季休暇、年末年始休暇もしっかり保証!
  • 様々な休暇制度(有給、慶弔、産前・産後、育児、バースデー休暇、有給6日取得で特別休暇付与)を完備!
  • 従業員の成長と健康を支援するための表彰制度、資格取得支援、健康促進手当など!
  • 生活を支えるテレワーク手当、記事寄稿手当、結婚祝金・出産祝金など、様々な手当を提供!
  • 自己啓発としての書籍購入制度や、メンバー間のコミュニケーションを深める交流費補助!
  • 成果に応じた決算賞与や、リファラル採用手当、AI手当など、頑張りをしっかり評価!
  • ワークライフバランスを重視し、副業もOK!

株式会社 ONE WEDGEでは、一人ひとりの従業員が自己実現できる環境を大切にしています。
共に成長し、刺激を与え合える仲間をお待ちしております。
あなたの能力と熱意を、ぜひ当社で発揮してください。
ご応募お待ちしております!

ホームページ、採用情報は下記ボタンからご確認ください!

応募、ご質問など、お問い合わせフォーム、またはX (旧Twitter)、InstagramのDMでお気軽にご相談ください♪

まとめ

TypeScriptの??演算子(Null合体演算子)は、nullundefinedを安全に処理するための強力なツールです。

この記事のポイントは以下の通りです。

  • ??演算子はnullundefinedのみを「空」として判定する
  • ||演算子とは異なり、0や”などの有効な値を保持できる
  • オプショナルチェーン(?.)と組み合わせることで、より安全なコードが書ける
  • APIレスポンスの処理や設定オブジェクトの初期化に特に有効
  • ES2020の標準機能でTypeScript 3.7以降で使用可能

??演算子を適切に使用することで、null/undefinedエラーを防ぎ、より堅牢なTypeScriptアプリケーションを構築できます。従来の||演算子との使い分けを理解し、それぞれの特性を活かした開発を心がけましょう。

COMMENT

メールアドレスが公開されることはありません。 が付いている欄は必須項目です