개발하다 보면 null이나 undefined 때문에 속 썩을 때가 많죠? 특히 타입스크립트에서는 이런 녀석들을 제대로 다루지 않으면 에러가 펑펑 터져요. 그래서 오늘은 타입스크립트에서 안전하게 코딩하는 데 필수적인 Nullish Coalescing Operator(??)와 Optional Chaining(?.)을 예제와 함께 꼼꼼히 파헤쳐 보겠습니다.
📑 목차
1. 안전한 타입 코딩, Nullish Coalescing과 Optional Chaining
타입스크립트(TypeScript)는 자바스크립트(JavaScript)에 정적 타입 시스템을 추가하여 코드의 안정성을 향상시키는 데 기여합니다. 본 가이드에서는 Nullish Coalescing Operator (??)와 Optional Chaining (?.)을 활용하여 타입 안정성을 확보하고, 잠재적인 오류를 방지하는 방법에 대해 심층적으로 분석합니다.
Nullish Coalescing Operator (??)는 좌항의 값이 null 또는 undefined일 경우에만 우항의 값을 반환합니다. 반면, Optional Chaining (?.)은 객체의 프로퍼티에 접근하기 전에 해당 프로퍼티가 null 또는 undefined인지 확인하고, null 또는 undefined일 경우 에러를 발생시키는 대신 undefined를 반환합니다. 이 두 기능은 코드를 간결하게 유지하면서 예외 상황에 안전하게 대처할 수 있도록 도와줍니다.
본 가이드는 개발자들이 Nullish Coalescing과 Optional Chaining을 실제 프로젝트에 효과적으로 적용할 수 있도록 돕는 것을 목표로 합니다. 이 가이드를 통해 얻을 수 있는 것은 다음과 같습니다.
- Nullish Coalescing Operator (??)와 Optional Chaining (?.)의 기본 개념과 활용법 이해
- 실제 코드 예제를 통한 적용 방법 학습
- 잠재적인 오류를 예방하고 코드의 안정성을 높이는 방법 습득
- 타입스크립트 코딩 스타일 개선
이어지는 섹션에서는 각 연산자의 상세한 사용법과 다양한 예제를 통해 실제 개발 환경에서의 활용 방안을 제시할 것입니다. 또한, 두 연산자를 함께 사용하여 더욱 안전하고 효율적인 코드를 작성하는 방법을 살펴볼 것입니다.
2. nullish와 undefined, 타입스크립트 에러 방지 핵심
타입스크립트에서 null과 undefined는 잠재적인 에러를 발생시키는 주요 원인입니다. 두 값은 모두 '값이 없음'을 나타내지만, 타입 시스템 내에서 미묘한 차이를 가집니다. 이러한 차이를 이해하고 적절하게 처리하는 것은 타입스크립트 코딩의 안정성을 높이는 데 매우 중요합니다.
null은 개발자가 명시적으로 '값이 없음'을 할당한 경우를 의미합니다. 반면 undefined는 변수가 선언되었지만 아직 값이 할당되지 않았거나, 존재하지 않는 객체 속성에 접근하려고 할 때 발생합니다. 타입스크립트에서는 strictNullChecks 옵션을 활성화하여 null과 undefined를 더 엄격하게 관리할 수 있습니다.
→ 2.1 strictNullChecks 활용
strictNullChecks 옵션을 활성화하면 타입스크립트는 null 또는 undefined가 할당될 수 있는 변수에 대해 명시적인 타입 검사를 요구합니다. 예를 들어, 문자열 또는 null을 가질 수 있는 변수는 string | null과 같이 유니온 타입으로 선언해야 합니다. 이를 통해 null 또는 undefined로 인해 발생하는 런타임 에러를 사전에 방지할 수 있습니다.
다음은 strictNullChecks가 활성화되었을 때 발생할 수 있는 에러의 예시입니다.
function greet(name: string) {
console.log(Hello, ${name.toUpperCase()}!);
}
let nullableName: string | null = null;
greet(nullableName); // Error: Argument of type 'string | null' is not assignable to parameter of type 'string'.
위 코드에서 greet 함수는 문자열 타입의 인수를 기대하지만, nullableName 변수는 string | null 타입이므로 타입 에러가 발생합니다. 이러한 에러를 방지하기 위해 null 체크 로직을 추가하거나 Nullish Coalescing Operator (??) 또는 Optional Chaining (?.)을 사용하여 코드를 안전하게 작성해야 합니다.
📌 핵심 요약
- ✓ ✓ null/undefined는 TS 에러 주원인
- ✓ ✓ strictNullChecks로 타입 검사 강화
- ✓ ✓ 유니온 타입으로 null 가능성 명시
- ✓ ✓ ?? 또는 ?.으로 안전한 코드 작성
3. Nullish Coalescing 연산자 (??) 사용법 3가지
Nullish Coalescing 연산자(??)는 좌항의 값이 null 또는 undefined일 경우에만 우항의 값을 반환합니다. 이는 변수에 기본값을 할당하거나, 값이 없을 경우 대체값을 제공하는 데 유용합니다. Nullish Coalescing 연산자(??)를 활용하면 코드의 가독성을 높이고, 불필요한 조건문 사용을 줄일 수 있습니다.
→ 3.1 기본값 할당
변수가 null 또는 undefined일 때 기본값을 할당하는 가장 기본적인 사용법입니다. 다음 예제는 사용자 이름이 null 또는 undefined일 경우 "Unknown"을 기본값으로 설정합니다.
const userName = null ?? "Unknown";
console.log(userName); // "Unknown"
위 코드는 userName이 null이므로, "Unknown"이 출력됩니다. 만약 userName에 실제 값이 있었다면, 해당 값이 출력됩니다.
→ 3.2 함수 파라미터 기본값 설정
함수 파라미터가 전달되지 않았거나 null 또는 undefined일 경우 기본값을 설정할 수 있습니다. 이는 함수 호출 시 누락된 파라미터에 대한 처리를 간편하게 해줍니다.
function greet(name: string | null | undefined) {
const message = "Hello, " + (name ?? "Guest");
console.log(message);
}
greet("Alice"); // "Hello, Alice"
greet(null); // "Hello, Guest"
greet(undefined); // "Hello, Guest"
greet 함수는 name 파라미터가 null 또는 undefined일 경우 "Guest"를 사용하여 인사말을 생성합니다. 따라서, null 또는 undefined 값이 입력될 경우에도 에러 없이 정상적으로 실행됩니다.
→ 3.3 객체 프로퍼티 접근 시 기본값 제공
객체의 프로퍼티가 존재하지 않거나 null 또는 undefined일 경우 기본값을 제공할 수 있습니다. 이는 객체 구조가 유동적인 경우에 유용하게 사용될 수 있습니다.
const user = {
name: "Bob",
age: null
};
const userAge = user.age ?? 0;
console.log("User age:", userAge); // User age: 0
위 예제에서 user 객체의 age 프로퍼티는 null입니다. 따라서, Nullish Coalescing 연산자(??)는 0을 반환하여 userAge 변수에 할당합니다. 이로써, 객체에 해당 프로퍼티가 존재하지 않더라도 안전하게 기본값을 사용할 수 있습니다.
4. Optional Chaining (?.) 활용, 깊은 객체 안전하게 접근하기
Optional Chaining 연산자(?.)는 객체의 속성이나 메서드에 접근하기 전에 해당 속성 또는 메서드가 nullish (null 또는 undefined)인지 확인합니다. 이를 통해 존재하지 않는 속성에 접근하려 할 때 발생하는 타입 에러를 방지할 수 있습니다. ?. 연산자는 속성 체인 중간에 nullish 값이 발견되면 즉시 undefined를 반환합니다.
?. 연산자는 다음과 같은 상황에서 유용합니다. API 응답 데이터처럼 구조가 불확실한 객체를 다룰 때, 또는 중첩된 객체의 특정 속성에 안전하게 접근해야 할 때 활용도가 높습니다. 이를 통해 불필요한 조건문 없이 코드를 간결하게 유지하면서도 안정성을 확보할 수 있습니다. Optional Chaining은 코드의 가독성을 높이고 잠재적인 에러 발생 가능성을 줄여줍니다.
→ 4.1 Optional Chaining 기본 사용법
Optional Chaining은 객체의 속성에 접근할 때 점(.) 대신 ?.을 사용하는 방식으로 적용됩니다. 예를 들어, user?.address?.street은 user 객체에 address 속성이 있고, address 객체에 street 속성이 있을 경우에만 street 값을 반환합니다. 만약 user 또는 address가 nullish라면 전체 표현식은 undefined를 반환합니다.
다음은 Optional Chaining을 사용하는 간단한 예시 코드입니다.
const user = {
name: 'John Doe',
address: {
street: '123 Main St'
}
};
const street = user?.address?.street;
console.log(street); // 출력: "123 Main St"
const city = user?.address?.city;
console.log(city); // 출력: undefined
→ 4.2 Optional Chaining과 함수 호출
Optional Chaining은 함수 호출에도 적용할 수 있습니다. 객체의 메서드가 존재할 경우에만 해당 메서드를 실행하고, 존재하지 않을 경우에는 undefined를 반환합니다. 예를 들어, user?.getName?.()은 user 객체에 getName 메서드가 존재할 경우에만 해당 메서드를 호출합니다.
아래 예시는 메서드가 존재하지 않을 때 에러를 방지하는 방법을 보여줍니다.
const user = {
name: 'John Doe'
};
const getName = user?.getName?.();
console.log(getName); // 출력: undefined
5. 타입스크립트 단축 평가, AND(&&) 와 OR(||) 함께 쓰기
타입스크립트에서 단축 평가는 코드를 간결하게 만들고 조건부 로직을 효과적으로 구현하는 데 사용됩니다. AND(&&) 연산자와 OR(||) 연산자는 JavaScript와 마찬가지로 타입스크립트에서도 단축 평가를 수행합니다. 이러한 단축 평가는 조건에 따라 코드 실행을 최적화하고, 불필요한 연산을 방지하는 데 유용합니다.
→ 5.1 AND(&&) 연산자를 활용한 조건부 실행
AND(&&) 연산자는 좌항이 truthy 값일 경우에만 우항을 평가합니다. 좌항이 falsy 값이라면 우항은 평가되지 않고 좌항의 값을 그대로 반환합니다. 이를 활용하여 특정 조건이 만족될 때만 코드를 실행하는 조건부 로직을 구현할 수 있습니다. 예를 들어, 객체의 특정 속성이 존재하는 경우에만 해당 속성에 접근하는 코드를 작성할 수 있습니다.
const user = {
name: 'John Doe',
profile: {
age: 30
}
};
const age = user.profile && user.profile.age;
console.log(age); // 30
const address = user.address && user.address.street;
console.log(address); // undefined
위 예제에서 user.profile이 존재할 때만 user.profile.age에 접근합니다. 만약 user.profile이 null 또는 undefined라면, user.profile.age는 평가되지 않고 undefined가 반환됩니다. 이를 통해 안전하게 객체 속성에 접근할 수 있습니다.
→ 5.2 OR(||) 연산자를 활용한 기본값 설정
OR(||) 연산자는 좌항이 falsy 값일 경우에만 우항을 평가합니다. 좌항이 truthy 값이라면 우항은 평가되지 않고 좌항의 값을 그대로 반환합니다. 이를 활용하여 변수에 기본값을 설정하거나, 대체 값을 제공하는 데 사용할 수 있습니다. 이는 변수가 null, undefined, '', 0, NaN 중 하나일 때 유용합니다.
function greet(name: string | undefined) {
const userName = name || 'Guest';
console.log(Hello, ${userName}!);
}
greet('John'); // Hello, John!
greet(undefined); // Hello, Guest!
위 예제에서 name이 undefined일 경우, userName은 'Guest'로 설정됩니다. name이 유효한 문자열이라면, 해당 문자열이 userName에 할당됩니다. 이처럼 OR(||) 연산자는 간단하게 기본값을 설정하는 데 효과적입니다.
→ 5.3 Nullish Coalescing 연산자(??)와의 비교
OR(||) 연산자는 falsy 값을 확인하는 반면, Nullish Coalescing 연산자(??)는 null 또는 undefined만을 확인합니다. 따라서 '' 또는 0과 같은 falsy 값을 기본값으로 사용해야 하는 경우에는 OR(||) 연산자가 적합합니다. 반면, null 또는 undefined에 대해서만 기본값을 설정하려면 Nullish Coalescing 연산자(??)를 사용하는 것이 좋습니다.
6. 주의! Nullish Coalescing과 Optional Chaining 잠재적 오류
Nullish Coalescing 연산자(??)와 Optional Chaining 연산자(?.)는 타입스크립트 코드를 간결하고 안전하게 만들어주지만, 잘못 사용하면 예상치 못한 오류를 발생시킬 수 있습니다. 특히, 연산자들의 동작 방식을 정확히 이해하지 못하거나, 타입 시스템의 허점을 이용하려는 시도가 있을 때 문제가 발생할 수 있습니다. 따라서 각 연산자의 동작 방식과 잠재적인 오류 발생 상황을 숙지하고, 코드 작성 시 주의를 기울여야 합니다.
→ 6.1 Nullish Coalescing 연산자 오해
Nullish Coalescing 연산자는 좌항이 null 또는 undefined일 경우에만 우항의 값을 반환합니다. 그러나 개발자들은 종종 이 연산자를 falsy 값(0, '', NaN 등)에 대한 기본값 설정에도 사용하려고 시도합니다. 이러한 오해는 예상치 못한 결과를 초래할 수 있습니다.
예를 들어, 다음 코드를 살펴보겠습니다. const count = 0; const displayCount = count ?? 10; console.log(displayCount); // 0 이 경우, count가 0임에도 불구하고 displayCount는 10이 아닌 0으로 설정됩니다. 이는 Nullish Coalescing 연산자가 0을 nullish 값으로 간주하지 않기 때문입니다.
따라서, falsy 값에 대한 기본값 설정을 위해서는 OR 연산자(||)를 사용하거나, 명시적인 조건문을 사용하는 것이 더 적절합니다.
→ 6.2 Optional Chaining 남용
Optional Chaining 연산자는 객체의 속성이나 메서드에 접근하기 전에 해당 속성 또는 메서드가 nullish인지 확인합니다. 하지만, 너무 광범위하게 Optional Chaining을 사용하는 것은 코드의 가독성을 떨어뜨리고, 잠재적인 오류를 숨길 수 있습니다.
예를 들어, 객체의 특정 속성이 항상 존재해야 한다고 가정할 때, Optional Chaining을 사용하는 것은 문제를 회피하는 것일 수 있습니다. 대신, 해당 속성이 존재하지 않는 경우에 대한 명시적인 오류 처리 로직을 추가하는 것이 더 나은 방법입니다. 다음과 같은 코드를 고려해볼 수 있습니다. const user = { address: { city: 'Seoul' } }; const street = user?.address?.street; if (!street) { throw new Error('Street address is missing'); }
→ 6.3 타입 단언(Type Assertion)과 함께 사용 시 주의
타입 단언은 타입스크립트에게 특정 변수의 타입을 개발자가 직접 지정하는 기능입니다. Nullish Coalescing 또는 Optional Chaining과 함께 타입 단언을 사용할 때, 타입 안정성이 저하될 수 있습니다. 타입 단언은 신중하게 사용해야 합니다.
다음과 같은 예시를 생각해 볼 수 있습니다. const name = (document.getElementById('name') as HTMLInputElement)?.value ?? 'default';
위 코드에서 document.getElementById('name') as HTMLInputElement는 id가 'name'인 HTML 요소를 HTMLInputElement 타입으로 단언합니다. 그러나, 만약 실제로 해당 요소가 존재하지 않거나, 다른 타입의 요소라면 런타임 에러가 발생할 수 있습니다. 따라서, 타입 단언을 사용하기 전에 해당 요소의 존재 여부와 타입을 확인하는 것이 좋습니다.
📌 핵심 요약
- ✓ ✓ ??, ?. 오용 시 오류 발생!
- ✓ ✓ ??는 falsy 값 처리 불가, || 활용
- ✓ ✓ ?. 남용은 오류를 숨길 수 있습니다.
- ✓ ✓ 타입 단언과 함께 쓸 때 주의 요망!
7. 더 나은 타입스크립트 코드를 위한 실천 전략
타입스크립트 코드를 개선하기 위한 실천 전략은 Nullish Coalescing 연산자(??)와 Optional Chaining 연산자(?.)를 효과적으로 활용하는 것에서 시작합니다. 이러한 연산자들을 올바르게 사용하면 코드의 가독성을 높이고, 잠재적인 오류를 줄일 수 있습니다. 여기서는 실제 개발에서 적용 가능한 몇 가지 전략을 제시합니다.
→ 7.1 명확한 기본값 설정
Nullish Coalescing 연산자(??)를 사용하여 변수에 null 또는 undefined가 할당될 경우, 명확한 기본값을 설정하는 것이 중요합니다. 이는 예상치 못한 동작을 방지하고 코드의 안정성을 높이는 데 기여합니다. 예를 들어, 사용자 설정 객체에서 폰트 크기를 가져올 때, 값이 null 또는 undefined인 경우 기본 폰트 크기를 설정할 수 있습니다.
interface UserSettings {
fontSize?: number;
}
const defaultSettings: UserSettings = { fontSize: 16 };
const getUserFontSize = (userSettings: UserSettings | null | undefined): number => {
const fontSize = userSettings?.fontSize ?? defaultSettings.fontSize;
return fontSize;
};
const currentUserSettings: UserSettings = { fontSize: null };
const fontSize = getUserFontSize(currentUserSettings); // fontSize는 16이 됩니다.
위 예제에서 userSettings?.fontSize ?? defaultSettings.fontSize는 userSettings 객체의 fontSize 속성이 null 또는 undefined일 경우, defaultSettings.fontSize 값을 반환합니다. 이를 통해 폰트 크기가 항상 유효한 숫자가 되도록 보장합니다.
→ 7.2 깊은 객체 구조 접근 시 안전성 확보
Optional Chaining 연산자(?.)를 활용하여 깊은 객체 구조에 안전하게 접근할 수 있습니다. 이는 중첩된 객체의 속성에 접근할 때, 중간 속성이 null 또는 undefined인 경우에도 에러가 발생하지 않도록 합니다. 따라서, API 응답과 같이 구조가 유동적인 데이터에 접근할 때 유용합니다.
interface APIResponse {
data?: {
user?: {
profile?: {
name?: string;
};
};
};
}
const response: APIResponse = { };
const userName = response.data?.user?.profile?.name ?? 'Unknown';
console.log(userName); // "Unknown" 출력
위 코드에서 response.data?.user?.profile?.name은 response 객체의 data, user, profile 속성이 존재하지 않더라도 에러를 발생시키지 않고 undefined를 반환합니다. Nullish Coalescing 연산자(??)를 통해 최종적으로 name이 nullish일 경우 'Unknown'이라는 기본값을 설정합니다.
→ 7.3 조건부 속성 접근 및 메서드 호출
Optional Chaining 연산자(?.)는 조건부로 객체의 속성에 접근하거나 메서드를 호출할 때도 유용합니다. 특정 조건이 충족될 때만 속성에 접근하거나 메서드를 실행해야 하는 경우, Optional Chaining 연산자를 사용하여 코드를 간결하게 만들 수 있습니다. 예를 들어, 객체가 특정 속성을 가지고 있을 때만 해당 속성의 값을 사용하는 경우에 활용할 수 있습니다.
interface Config {
callback?: () => void;
}
const config: Config = {};
config.callback?.(); // config.callback이 함수인 경우에만 실행
위 예제에서 config.callback?.()는 config 객체의 callback 속성이 함수인 경우에만 해당 함수를 실행합니다. callback 속성이 존재하지 않거나 함수가 아닌 경우, 아무런 동작도 수행하지 않습니다. 이를 통해 불필요한 조건문 없이 안전하게 메서드를 호출할 수 있습니다.
오늘부터 안전한 타입 코딩 마스터하기
이제 Nullish Coalescing과 Optional Chaining을 활용하여 타입스크립트 코드를 더욱 안전하고 효율적으로 관리할 수 있습니다. 오늘 배운 내용을 바탕으로 null과 undefined로 인한 잠재적 오류를 줄이고, 더욱 안정적인 애플리케이션을 개발해보세요. 꾸준한 연습과 적용으로 타입스크립트 실력을 한 단계 더 발전시켜 보세요!
📌 안내사항
- 본 콘텐츠는 정보 제공 목적으로 작성되었습니다.
- 법률, 의료, 금융 등 전문적 조언을 대체하지 않습니다.
- 중요한 결정은 반드시 해당 분야의 전문가와 상담하시기 바랍니다.
'IT' 카테고리의 다른 글
| n8n 초보자, 5분 자동화 레시피: GitHub 이슈 알림 받기 (0) | 2026.05.03 |
|---|---|
| 클린 아키텍처 구현, 핵심 원칙 3가지 - 의존성 규칙, Use Case, 엔티티 (0) | 2026.05.02 |
| 홈서버 구축자를 위한 Docker Compose, YAML 설정부터 배포까지 (0) | 2026.04.30 |
| JSON 파일 예쁘게 포맷팅, CLI 도구 5가지 비교 분석 (1) | 2026.04.29 |
| LoRaWAN 네트워크 구축, 아두이노 연동 및 데이터 시각화 DIY 가이드 (0) | 2026.04.28 |