読み込み中...

【TypeScript】論理演算子の活用例10選!初心者でも分かる完全ガイド

TypeScriptの論理演算子をわかりやすく解説するイラスト TypeScript
この記事は約20分で読めます。

【サイト内のコードはご自由に個人利用・商用利用いただけます】

この記事では、プログラムの基礎知識を前提に話を進めています。

説明のためのコードや、サンプルコードもありますので、もちろん初心者でも理解できるように表現してあります。

本記事のサンプルコードを活用して機能追加、目的を達成できるように作ってありますので、是非ご活用ください。

※この記事は、一般的にプロフェッショナルの指標とされる『実務経験10,000時間以上』を満たす現役のプログラマチームによって監修されています。

※Japanシーモアは、常に解説内容のわかりやすさや記事の品質に注力しております。不具合、分かりにくい説明や不適切な表現、動かないコードなど気になることがございましたら、記事の品質向上の為にお問い合わせフォームにてご共有いただけますと幸いです。
(送信された情報は、プライバシーポリシーのもと、厳正に取扱い、処分させていただきます。)

はじめに

TypeScriptは、JavaScriptのスーパーセットとして登場したプログラミング言語です。

型の概念を取り入れることで、コードの品質向上やエラーの早期発見が可能となり、開発の効率化に寄与しています。

TypeScriptにおいても、論理演算子は非常に基本的な部分を担っており、日々の開発において頻繁に利用されます。

この記事では、TypeScriptでの論理演算子の基本から応用までを、初心者の方にもわかりやすく解説していきます。

具体的なサンプルコードを交えながら、どのように活用するのか、注意点は何か、カスタマイズや応用例といった内容も盛り込んでいます。

初めてTypeScriptを学ぶ方はもちろん、すでに使用経験がある方も、新しい知見を得ることができるでしょう。

●TypeScriptの論理演算子とは

TypeScriptにおける論理演算子は、複数の条件や式を組み合わせて真偽値を返すための演算子です。

これらの演算子は、条件式やブール演算において非常に頻繁に使われるもので、プログラムのフローコントロールに欠かせない存在です。

○論理演算子の基本

TypeScriptでは、主に3つの論理演算子が用意されています。

それぞれの演算子と、その動作について詳しく見ていきましょう。

□&& (AND)

&& はAND演算子と呼ばれ、左側と右側の両方の条件が真である場合に真を返します。

一方、いずれか一方または両方が偽であれば、偽を返します。

このコードでは、変数abを使って&&の動作を表しています。

この例では、abの両方が真である場合、結果としてtrueが出力されます。

let a = true;
let b = true;
let result = a && b; 
console.log(result); // trueが出力される

上記のコードでは、abも真なので、resultも真となり、trueがコンソールに出力されます。

□|| (OR)

|| はOR演算子と呼ばれ、左側または右側のどちらか一方が真であれば真を返します

。両方が偽である場合のみ、偽を返します。

このコードでは、変数cdを使って||の動作を表しています。

この例では、cまたはdのいずれか一方が真である場合、結果としてtrueが出力されます。

let c = false;
let d = true;
let result2 = c || d; 
console.log(result2); // trueが出力される

上記のコードでは、cは偽、dは真なので、result2は真となり、trueがコンソールに出力されます。

□! (NOT)

! はNOT演算子と呼ばれ、与えられた条件の真偽を反転させます。

すなわち、真が与えられた場合は偽を、偽が与えられた場合は真を返します。

このコードでは、変数eを使って!の動作を表しています。

この例では、eが真である場合、結果としてfalseが出力されます。

let e = true;
let result3 = !e; 
console.log(result3); // falseが出力される

上記のコードでは、eは真なので、result3は偽となり、falseがコンソールに出力されます。

●TypeScriptでの論理演算子の使い方

論理演算子を効果的に活用することで、プログラムのロジックを簡潔かつ明瞭に表現することができます。

その具体的な使い方をサンプルコードを交えて解説します。

○サンプルコード1:変数の値をチェックして条件を満たすか確認する

下記のサンプルコードでは、変数ageisStudentを使って、年齢が20歳以上かつ学生でない場合に、成人の学生ではないことを確認します。

let age = 25;
let isStudent = false;

if (age >= 20 && !isStudent) {
    console.log("成人の学生ではありません");
}

このコードでは、&&を使ってage >= 20!isStudentの2つの条件を組み合わせています。

この例では、ageが20以上で、かつisStudentがfalseの場合、つまり学生でない場合に、成人の学生ではありませんというメッセージがコンソールに出力されます。

実際に上記のコードを実行すると、変数ageは25と定義されており、isStudentはfalseと定義されているため、条件式age >= 20 && !isStudentは真と評価されます。

その結果、成人の学生ではありませんというメッセージがコンソールに表示されることとなります。

○サンプルコード2:複数の条件を組み合わせて確認する

TypeScriptにおける論理演算子は、複数の条件を組み合わせて論理的な評価を行う際に非常に役立ちます。

今回は、その活用方法について、具体的なサンプルコードとともに詳しく解説します。

まず、基本的な論理演算子である &&(AND)、||(OR)、!(NOT)を、複数の条件と組み合わせて使用する方法を紹介します。

// TypeScriptのサンプルコード
const age = 25;
const hasDriverLicense = true;
const hasHistoryOfAccident = false;

// 20歳以上で、運転免許を持っている、かつ、事故歴がないかを確認する
const canRentCar = age >= 20 && hasDriverLicense && !hasHistoryOfAccident;
console.log(canRentCar); // true

このコードでは、agehasDriverLicensehasHistoryOfAccidentという3つの変数を用意しています。

canRentCarという変数には、3つの条件を組み合わせた結果を代入しています。

具体的には、「20歳以上」、かつ「運転免許を持っている」、そして「事故歴がない」ことを確認しています。

ここで、&&(AND)演算子は、その左右の条件が両方ともtrueである場合にtrueを返します。

一方、!(NOT)演算子は、後ろの条件がfalseである場合にtrueを返します。

この例では、3つの条件がすべてtrueであるため、canRentCarはtrueとなります。

このサンプルコードを実行すると、canRentCarの値がコンソールに出力されます。

すなわち、上記の条件がすべて満たされている場合、コンソールにはtrueと表示されます。

○サンプルコード3:関数の戻り値を使った条件チェック

TypeScriptでの論理演算子の利用シーンとして、「関数の戻り値を使った条件チェック」が考えられます。

関数の戻り値はしばしば条件分岐や変数の代入などで使われるため、論理演算子を効果的に活用することでコードの可読性や保守性を向上させることができます。

関数の戻り値を使って条件をチェックするシンプルなサンプルコードを紹介します。

function isPositiveNumber(num: number): boolean {
    return num > 0;
}

function isEvenNumber(num: number): boolean {
    return num % 2 === 0;
}

const checkValue = (value: number) => {
    if (isPositiveNumber(value) && isEvenNumber(value)) {
        console.log('与えられた数値は正の偶数です。');
    } else {
        console.log('与えられた数値は正の偶数ではありません。');
    }
}

checkValue(10);

このコードでは、まずisPositiveNumber関数とisEvenNumber関数を定義しています。

これらの関数はそれぞれ、与えられた数値が正の数値であるか、偶数であるかを判断し、その結果を論理値として返します。

そして、checkValue関数を定義し、この関数内で先ほどの2つの関数の戻り値を活用して条件チェックを行っています。

この例では、論理演算子&&を使って、与えられた数値が正の偶数であるかを確認しています。

上記のサンプルコードを実行すると、次のような結果が出力されます。

与えられた数値は正の偶数です。

この結果が得られるのは、checkValue関数に与えられた値10が、正の偶数であるためです。

また、論理演算子を活用して関数の戻り値をチェックする際の応用例として、複数の関数を組み合わせて更に複雑な条件を作成することが考えられます。

例えば、次のように3つの関数の戻り値を組み合わせることで、正の偶数でかつ10以下の数値であるかをチェックすることができます。

function isLessThanTen(num: number): boolean {
    return num <= 10;
}

const advancedCheckValue = (value: number) => {
    if (isPositiveNumber(value) && isEvenNumber(value) && isLessThanTen(value)) {
        console.log('与えられた数値は正の偶数でかつ10以下です。');
    } else {
        console.log('与えられた数値は上述の条件を満たしていません。');
    }
}

advancedCheckValue(8);

このコードの実行結果は、「与えられた数値は正の偶数でかつ10以下です。」となります。

●論理演算子の応用例

○サンプルコード4:複雑な条件を一つにまとめる

TypeScriptの論理演算子は、単一の条件だけでなく、複数の条件を組み合わせて一つの条件式として評価することも可能です。

これにより、コードの可読性や保守性が向上します。

例として、ユーザーが特定の条件をすべて満たす場合に特典を与えるプログラムを考えます。

function shouldReceiveBonus(user: { age: number, isEmailVerified: boolean, lastLogin: Date }): boolean {
    const oneWeekAgo = new Date();
    oneWeekAgo.setDate(oneWeekAgo.getDate() - 7);

    // 複雑な条件を論理演算子を使って一つの条件式にまとめる
    return user.age >= 18 && user.isEmailVerified && user.lastLogin > oneWeekAgo;
}

// 例のユーザー
const user1 = { age: 20, isEmailVerified: true, lastLogin: new Date('2023-08-20') };
const user2 = { age: 16, isEmailVerified: true, lastLogin: new Date('2023-08-18') };

console.log(shouldReceiveBonus(user1));  // true
console.log(shouldReceiveBonus(user2));  // false

上記のコードを実行すると、shouldReceiveBonus関数はuser1に対してtrueを返し、user2に対してfalseを返します。

これは、user1がすべての条件を満たしているのに対し、user2は年齢の条件を満たしていないためです。

このように、論理演算子を活用することで、複数の条件を簡潔に一つの条件式にまとめることができます。

これにより、コードの可読性が向上し、プログラムのロジックが一目瞭然となります。

○サンプルコード5:短絡評価を活用した条件分岐

短絡評価(short-circuit evaluation)は、論理演算子を使用したときに、式全体の真偽値が既に決定した場合、残りの評価をスキップする挙動を指します。

TypeScriptにおいても、JavaScriptと同じく、短絡評価の性質を持つ論理演算子が提供されています。

例えば、短絡評価を活用すると、次のようなメリットがあります。

  1. コードの実行時間を短縮:全ての条件を評価する必要がなく、必要な部分のみを評価するため、処理が早くなることがある。
  2. コードの可読性向上:条件を連鎖的に記述することができるため、コードが簡潔になることが多い。

次のサンプルコードは、短絡評価を活用して、条件分岐を行う例です。

// サンプルデータ
let user = {
  name: "Taro",
  age: 25,
  isAdmin: true
};

// 短絡評価を用いた条件分岐
let message = user && user.isAdmin && "管理者です";

console.log(message);  // "管理者です"

このコードでは、userオブジェクトが存在し、その中のisAdminプロパティがtrueである場合、"管理者です"というメッセージを生成しています。

具体的には、次の手順で評価が進行します。

  1. usertrueとして評価される。(オブジェクトはtruthyな値として扱われる)
  2. user.isAdmintrueとして評価される。
  3. これにより、"管理者です"という文字列がmessage変数に代入される。

上記のコードを実行すると、”管理者です”という文字列が出力されるのを確認することができます。

また、短絡評価は、関数の実行を制御する際にも有効にも活用できます。

function logAdminActions() {
  console.log("管理者のアクションをログします");
}

user && user.isAdmin && logAdminActions();

この例では、userが存在し、isAdmintrueである場合のみ、logAdminActions関数を実行します。

上記のコードを実行すると、”管理者のアクションをログします”というメッセージが出力されるのを確認できます。

○サンプルコード6:オプショナルチェイニングとの併用

TypeScriptでの開発を進めていると、オブジェクトのネストされたプロパティやメソッドにアクセスしたい場面が頻繁に出てきます。

しかし、そのネストされたプロパティやメソッドが存在しない場合には、エラーが発生します。

このような場合に役立つのが、オプショナルチェイニング(?.)です。

オプショナルチェイニングを使うことで、プロパティやメソッドが存在しない場合でも、エラーを回避し、undefinedを返すことができます。

この機能を論理演算子と併用することで、更にコードの柔軟性を高めることができます。

このコードでは、オプショナルチェイニングと論理演算子を使って、オブジェクトのプロパティの有無を確認し、存在しない場合はデフォルト値を返す例を示しています。

type UserProfile = {
  name?: string;
  address?: {
    city?: string;
    country?: string;
  };
};

const user: UserProfile = {
  name: "太郎",
  address: {
    country: "日本"
  }
};

const cityName = user.address?.city || "都市情報がありません";
console.log(cityName);  // この例では、cityプロパティが存在しないので、「都市情報がありません」と表示されます。

上記のサンプルコードのUserProfile型は、nameaddressというプロパティを持っていますが、これらのプロパティはオプショナルです。

そのため、これらのプロパティが存在しない可能性があります。

このような場合、直接user.address.cityのようにアクセスしようとすると、addressが存在しない場合にエラーが発生します。

しかし、オプショナルチェイニングを使用することで、addressが存在しない場合でもエラーが発生せずにundefinedが返されるため、安全にアクセスすることができます。

そして、論理演算子||を使用して、undefinedの場合にはデフォルト値「都市情報がありません」を返すようにしています。

このようにオプショナルチェイニングと論理演算子を組み合わせることで、エラーのリスクを減少させながら、柔軟なコードを書くことができます。

上記のコードを実行すると、cityプロパティが存在しないため、”都市情報がありません”というメッセージがコンソールに表示されるでしょう。

○サンプルコード7:型ガードとしての活用

TypeScriptは、静的型チェックを提供するJavaScriptのスーパーセットとして知られています。

この静的型チェックのメリットは、コンパイル時に型のエラーを検出できる点にあります。

しかし、実行時に動的に型を確認する必要がある場合もあります。こうした場合に便利なのが、「型ガード」という機能です。

型ガードは、特定の条件が真である場合に、その変数の型が狭められる、あるいは変更される仕組みを提供します。

論理演算子を使用して型ガードを活用する方法について見ていきましょう。

まずは、具体的なサンプルコードを用意しました。

こちらをご覧ください。

interface Cat {
    type: 'cat';
    meow(): void;
}

interface Dog {
    type: 'dog';
    bark(): void;
}

type Animal = Cat | Dog;

function isCat(animal: Animal): animal is Cat {
    return animal.type === 'cat';
}

let pet: Animal = { type: 'cat', meow: () => console.log("にゃーん") };

if (isCat(pet)) {
    pet.meow(); // この中ではpetはCatとして扱われる
}

このコードでは、CatDogという2つのインターフェースを定義しています。

これらのどちらか一方の型を持つ変数をAnimalとして定義しています。

isCatという関数は、引数として渡された動物が猫(Cat)であるかどうかを確認する型ガード関数です。

この例では、petという変数がAnimal型として宣言されていますが、実際にはCat型のオブジェクトを代入しています。

isCat関数を使用してpetCat型であるかどうかを確認すると、その後のif文の中でpetCat型として扱われるため、meowメソッドを呼び出すことができます。

このコードを実際に実行すると、「にゃーん」というテキストがコンソールに表示されることが期待されます。

これは、pet変数がCat型であると正しく認識され、その結果としてmeowメソッドが呼び出されるからです。

このように、型ガードは論理演算子と併用することで、変数の型を動的に確認し、特定の型に絞り込むことができる非常に便利な機能です。

特に、共用体(union type)を使用している場合や、実行時に型を動的に確認する必要がある場面での活用が推奨されます。

●論理演算子の注意点と対処法

○短絡評価による予期しない動作

TypeScriptでの論理演算子の使用において、短絡評価は一般的な課題として認識されています。

短絡評価とは、論理演算の結果が既に決定された場合、残りの評価をスキップする動作のことを指します。

この特性により、意図しない動作やバグが発生することがあります。

例えば、次のコードでは、関数functionAfunctionBの両方が実行されると期待されるかもしれませんが、実際にはfunctionAfalseを返す場合、functionBは実行されません。

if (functionA() && functionB()) {
  console.log("両関数は真を返しました");
}

このコードでは、functionAfalseを返すと、&&の短絡評価のためfunctionBは評価されずスキップされます。

このような短絡評価による予期しない動作を避けるための対処方法としては、複数の条件式を独立したif文に分けるという方法があります。

○nullとundefinedの取り扱い

TypeScriptにおいて、nullundefinedは異なる値ですが、論理演算子の文脈では両者ともfalseとして評価されます。

そのため、これらの値の取り扱いに注意が必要です。

サンプルコードを見てみましょう。

const value: number | null = getValue();

if (value) {
  console.log("valueは真の値です");
} else {
  console.log("valueは偽の値です");
}

このコードでは、getValue関数がnullを返す場合、”valueは偽の値です”というログが出力されます。

しかし、valueが0の場合も同じログが出力される点に注意が必要です。

このような混乱を避けるためには、具体的な値を明示的にチェックする方法がおすすめです。

例えば、次のようにvaluenullであるかどうかを明示的に確認することで、意図しない動作を避けることができます。

if (value !== null) {
  console.log("valueはnullではありません");
} else {
  console.log("valueはnullです");
}

この例では、valueが0であっても”valueはnullではありません”というログが正しく出力されます。

●TypeScriptの論理演算子のカスタマイズ方法

TypeScriptを使う上で、論理演算子の活用は避けて通れないテーマです。

しかし、TypeScriptが持つ型システムをフルに活用することで、より柔軟に、そして安全に論理演算を行う方法があります。

その中でも、ユーザー定義の型ガードを活用した論理演算は特に強力です。このセクションでは、その方法を詳しく解説していきます。

○ユーザー定義の型ガードを活用した論理演算

ユーザー定義の型ガードとは、TypeScriptで型を狭くするためのカスタム関数を意味します。

この機能を使うと、論理演算を独自に拡張することができます。

例として、あるオブジェクトが特定のプロパティを持っているかどうかを確認する型ガードを考えてみましょう。

// オブジェクトにnameプロパティが存在するかチェックする型ガード
function hasName(obj: any): obj is { name: string } {
    return !!obj && typeof obj.name === "string";
}

このコードでは、hasNameという関数を使って、任意のオブジェクトにnameという文字列型のプロパティが存在するかどうかをチェックしています。

この例では、obj is { name: string }という型アサーションを使って、関数の戻り値がtrueの場合、objの型が{ name: string }であることをTypeScriptに伝えています。

この型ガードを利用して、次のようにオブジェクトが特定のプロパティを持っているかどうかを確認する論理演算を行うことができます。

const obj = { name: "Taro", age: 25 };

if (hasName(obj)) {
    console.log(obj.name); // ここではobjの型が{ name: string }として認識される
}

この例では、hasName関数を使ってobjnameプロパティを持っているかをチェックしています。

hasName関数がtrueを返すと、その後のブロック内ではobjの型が{ name: string }として認識され、obj.nameに安全にアクセスすることができます。

これにより、TypeScriptの型システムを活用して、カスタムの論理演算を行うことができるようになりました。

このような型ガードを活用することで、より柔軟で、かつ型安全なコードを書くことが可能です。

まとめ

TypeScriptにおける論理演算子の活用は、プログラミングにおいて極めて重要です。

本記事では、TypeScriptの論理演算子に関する基本的な知識から応用技術までを徹底的に解説しました。

TypeScriptを使用する際、論理演算子は避けて通れないテーマです。

今回の記事を通じて、その使い方や活用法、注意点などをしっかりと理解し、実践的なコードを書く力を身につけていただければ幸いです。

これからもTypeScriptの開発において、効果的な論理演算子の活用を心がけてください。