Optional chaining (?.) と Nullish coalescing operator (??) の比較
TypeScriptにおけるセーフナビゲーション演算子(?.)とnullプロパティパス
セーフナビゲーション演算子は、プロパティが存在しない場合でもエラーが発生せずにnullまたはundefinedを返す演算子です。
const obj = {
name: "John",
age: 30,
};
const name = obj?.name; // "John"
const age = obj?.address?.city; // undefined
// エラーが発生しない
console.log(name); // "John"
console.log(age); // undefined
nullプロパティパスは、プロパティチェーン内のnullまたはundefinedを無視して、存在するプロパティにアクセスするための構文です。
const obj = {
name: "John",
address: {
city: "New York",
},
};
const city = obj?.address?.city; // "New York"
// 従来の書き方
const city2 = obj.address && obj.address.city; // "New York"
// nullプロパティパスの方が簡潔で読みやすい
console.log(city); // "New York"
console.log(city2); // "New York"
セーフナビゲーション演算子とnullプロパティパスの使い分け
セーフナビゲーション演算子は、単一のプロパティにアクセスする場合に便利です。一方、nullプロパティパスは、プロパティチェーン内の複数のプロパティにアクセスする場合に便利です。
例
const obj = {
name: "John",
address: {
city: "New York",
},
};
// セーフナビゲーション演算子
const name = obj?.name; // "John"
// nullプロパティパス
const city = obj?.address?.city; // "New York"
// 複数のプロパティにアクセスする場合
const fullName = obj?.name?.toUpperCase(); // "JOHN"
const address = obj?.address?.city?.toUpperCase(); // "NEW YORK"
セーフナビゲーション演算子とnullプロパティパスは、TypeScriptでnullまたはundefinedの可能性のあるプロパティに安全にアクセスするための便利なツールです。これらのツールを使いこなすことで、コードをより簡潔で読みやすくすることができます。
// オブジェクト
const person = {
name: "John",
age: 30,
address: {
city: "New York",
state: "NY",
},
};
// セーフナビゲーション演算子
const name = person?.name; // "John"
const age = person?.age; // 30
const city = person?.address?.city; // "New York"
const state = person?.address?.state; // "NY"
// nullプロパティパス
const fullName = person?.name?.toUpperCase(); // "JOHN"
const address = person?.address?.city?.toUpperCase(); // "NEW YORK"
// 存在しないプロパティへのアクセス
const nonExistingProperty = person?.nonExistingProperty; // undefined
// nullまたはundefinedの場合のデフォルト値
const defaultName = person?.name ?? "Unknown"; // "John"
const defaultAge = person?.age ?? 0; // 30
const defaultCity = person?.address?.city ?? "Unknown City"; // "New York"
// オプションの引数
function greet(person: { name?: string }): string {
return person?.name ?? "Hello, stranger!";
}
const greeting = greet(person); // "Hello, John!"
// ネストされたオブジェクト
const nestedObject = {
data: {
value: 10,
},
};
const value = nestedObject?.data?.value; // 10
// 配列
const numbers = [1, 2, 3, 4, 5];
const firstNumber = numbers?.[0]; // 1
const lastNumber = numbers?.[numbers.length - 1]; // 5
// 存在しない要素へのアクセス
const nonExistingElement = numbers?.[100]; // undefined
// nullまたはundefinedの場合のデフォルト値
const defaultValue = numbers?.[0] ?? 0; // 1
// オプションの要素
function sum(numbers: number[]): number {
return numbers?.[0] ?? 0 + numbers?.[1] ?? 0;
}
const sumOfFirstTwoNumbers = sum([1, 2]); // 3
// マップ
const map = new Map([
["key1", "value1"],
["key2", "value2"],
]);
const value1 = map?.get("key1"); // "value1"
const value2 = map?.get("key2"); // "value2"
// 存在しないキーへのアクセス
const nonExistingKey = map?.get("nonExistingKey"); // undefined
// nullまたはundefinedの場合のデフォルト値
const defaultValue2 = map?.get("key1") ?? "default value"; // "value1"
// オプションのキー
function getValue(map: Map<string, string>, key: string): string {
return map?.get(key) ?? "default value";
}
const valueFromMap = getValue(map, "key1"); // "value1"
// Set
const set = new Set([1, 2, 3, 4, 5]);
const hasValue1 = set?.has(1); // true
const hasValue2 = set?.has(2); // true
// 存在しない値へのアクセス
const nonExistingValue = set?.has(100); // false
// オプションの値
function hasValue(set: Set<number>, value: number): boolean {
return set?.has(value) ?? false;
}
const hasValueInSet = hasValue(set, 1); // true
TypeScriptでnullまたはundefinedの可能性のあるプロパティにアクセスする他の方法
従来のnullチェック
const obj = {
name: "John",
age: 30,
};
const name = obj.name;
if (name === null || name === undefined) {
// nameはnullまたはundefined
} else {
// nameはnullまたはundefinedではない
}
const age = obj.age;
if (age === null || age === undefined) {
// ageはnullまたはundefined
} else {
// ageはnullまたはundefinedではない
}
Optional chainingは、JavaScriptの提案機能であり、TypeScript 4.0以降で使用できます。
const obj = {
name: "John",
age: 30,
};
const name = obj?.name; // "John"
const age = obj?.age; // 30
// 存在しないプロパティへのアクセス
const nonExistingProperty = obj?.nonExistingProperty; // undefined
// nullまたはundefinedの場合のデフォルト値
const defaultName = obj?.name ?? "Unknown"; // "John"
const defaultAge = obj?.age ?? 0; // 30
const obj = {
name: "John",
age: 30,
};
const name = obj.name ?? "Unknown"; // "John"
const age = obj.age ?? 0; // 30
// 存在しないプロパティへのアクセス
const nonExistingProperty = obj.nonExistingProperty ?? "Unknown"; // "Unknown"
エラーハンドリング
const obj = {
name: "John",
age: 30,
};
try {
const name = obj.name;
const age = obj.age;
// nameとageを使用する
} catch (error) {
// エラー処理
}
型ガード
const obj: { name?: string; age?: number } = {
name: "John",
};
if (obj.name !== null && obj.name !== undefined) {
const name = obj.name;
// nameを使用する
}
if (obj.age !== null && obj.age !== undefined) {
const age = obj.age;
// ageを使用する
}
これらの方法にはそれぞれメリットとデメリットがあります。状況に応じて適切な方法を選択する必要があります。
typescript