조아마시

쓸모 있는 상세페이지 만들기

웹개발/typescript

[타입스크립트] null과 undefined

joamashi 2024. 8. 30. 22:00

nullundefined는 자바스크립트에서도 자주 등장하는 개념이지만, 타입스크립트에서는 더욱 엄격하게 관리됩니다. 두 값은 비슷해 보이지만 미묘한 차이가 있고, 코드의 안정성을 위해 올바르게 이해하고 사용하는 것이 중요합니다.

null과 undefined의 개념

  • undefined:
    • 변수가 선언되었지만 값이 할당되지 않은 상태를 의미합니다.
    • 함수에서 값을 반환하지 않거나, 객체의 프로퍼티가 존재하지 않을 때 undefined가 할당됩니다.
  • null:
    • 의도적으로 값이 없음을 나타내기 위해 할당하는 값입니다.
    • 객체가 존재하지 않거나, 특정 값이 없음을 나타낼 때 null을 사용합니다.

왜 null과 undefined를 구분해야 할까요?

  • 타입 안정성: 타입스크립트는 변수의 타입을 명확히 지정하여 오류를 미리 방지합니다. null과 undefined를 구분하여 더욱 정확한 타입 검사를 수행할 수 있습니다.
  • 코드 가독성: 코드를 읽는 사람이 변수의 상태를 명확하게 파악할 수 있도록 도와줍니다.
  • null 체크: null 또는 undefined 값을 확인하지 않고 사용하면 예상치 못한 오류가 발생할 수 있습니다. 타입스크립트는 null 체크를 강제하여 안전한 코드를 작성하도록 유도합니다.

다양한 예시

// undefined 예시
let message; // 선언만 되고 값이 할당되지 않아 undefined
console.log(message); // undefined

function greet(name: string): string {
  if (name) {
    return `Hello, ${name}!`;
  }
  // 인자가 없으면 undefined를 반환
}

// null 예시
let user: { name: string; age: number } = null; // 객체 자체가 없음
console.log(user?.name); // undefined (옵셔널 체이닝)

let data: string[] = [];
let firstItem = data[0]; // undefined (배열에 요소가 없음)

// null과 undefined를 함께 사용하는 예시
function getLength(value: string | null | undefined): number {
  if (value === null || value === undefined) {
    return 0;
  }
  return value.length;
}

타입스크립트에서 null과 undefined를 다루는 방법

  • 옵셔널 타입: ?를 사용하여 변수나 프로퍼티가 null 또는 undefined일 수 있음을 나타냅니다.
  • 유니온 타입: |를 사용하여 여러 타입 중 하나일 수 있음을 나타냅니다.
  • null 체크: if 문이나 널 병합 연산자(??)를 사용하여 null 또는 undefined 값을 확인합니다.
  • Non-null assertion: !를 사용하여 변수가 절대 null 또는 undefined가 아니라고 확신할 때 사용합니다. (주의: 오용하면 오류 발생 가능성이 있습니다.)

요약

타입스크립트에서 null과 undefined는 명확한 차이를 가지며, 코드의 안정성을 위해 올바르게 사용해야 합니다. 옵셔널 타입, 유니온 타입, null 체크 등 다양한 기능을 활용하여 null과 undefined를 효과적으로 관리할 수 있습니다.

핵심:

  • undefined는 값이 할당되지 않은 상태, null은 의도적으로 값이 없음을 나타냅니다.
  • 타입스크립트는 null과 undefined를 구분하여 더욱 안전한 코드를 작성할 수 있도록 도와줍니다.
  • 옵셔널 타입, 유니온 타입, null 체크 등 다양한 기능을 활용하여 null과 undefined를 관리합니다.

타입스크립트에서는 null과 undefined를 명확하게 구분하고 안전하게 사용하기 위해 다양한 방법을 제공합니다. 이전 설명에 이어, 좀 더 자세한 예시와 함께 다양한 선언 방식을 살펴보겠습니다.

1. 옵셔널 타입 (Optional Type)

  • 변수나 프로퍼티에 ?를 붙여 null 또는 undefined 값을 허용합니다.
interface User {
  name?: string; // name은 선택적(optional)입니다.
  age: number;
}

let user: User = { age: 30 }; // name은 undefined가 될 수 있습니다.

2. 유니온 타입 (Union Type)

  • 여러 타입 중 하나의 값을 가질 수 있도록 합니다.
let value: string | number | null = null; // value는 string, number, null 중 하나일 수 있습니다.

function greet(name: string | null): void {
  if (name) {
    console.log(`Hello, ${name}!`);
  } else {
    console.log('Hello, world!');
  }
}

3. null과 undefined를 모두 포함하는 타입

  • null과 undefined를 함께 사용해야 할 경우, 유니온 타입으로 표현합니다.
  • TypeScript에서는 null과 undefined를 서로 할당 가능한 타입으로 간주합니다.
let value: string | null | undefined = undefined;

4. Non-null Assertion Operator (!)

  • 변수가 절대 null 또는 undefined가 아니라고 확신할 때 사용합니다.
  • 주의: 오용하면 runtime error가 발생할 수 있으므로 신중하게 사용해야 합니다.
function len(s: string): number {
  return s!.length; // s가 반드시 문자열이라고 확신하는 경우
}

5. 타입 가드 (Type Guard)

  • 변수의 타입을 확인하여 안전하게 값에 접근합니다.
  • typeof, instanceof, custom type guard 등을 사용합니다.
function isString(x: any): x is string {
  return typeof x === 'string';
}

function processData(x: string | number) {
  if (isString(x)) {
    // x는 확실히 string 타입입니다.
    console.log(x.length);
  } else {
    // x는 확실히 number 타입입니다.
  }
}

6. TypeScript 설정 (strictNullChecks)

  • tsconfig.json 파일에서 strictNullChecks 옵션을 true로 설정하면 null과 undefined를 더욱 엄격하게 검사합니다.
  • 이 옵션을 활성화하면 null 또는 undefined 값을 할당하려 할 때 컴파일 에러가 발생합니다.

추가적으로 알아두면 좋은 점

  • **옵셔널 체이닝 (?.)**을 사용하면 null 또는 undefined 값에 안전하게 접근할 수 있습니다.
  • **널 병합 연산자 (??)**는 null 또는 undefined 값이 아닌 첫 번째 값을 반환합니다.
  • TypeScript의 타입 시스템은 매우 유연하며, 다양한 상황에 맞춰 사용할 수 있습니다.

어떤 방식을 선택해야 할까요?

  • 가장 일반적인 경우: 옵셔널 타입과 유니온 타입을 조합하여 사용합니다.
  • 확실히 null 또는 undefined가 아닐 때: Non-null assertion operator를 사용합니다. (신중하게 사용해야 합니다)
  • 복잡한 타입 검사: 타입 가드를 사용합니다.
  • 프로젝트 전체의 타입 안정성: strictNullChecks 옵션을 활성화합니다.

예시:

interface Product {
  name: string;
  price?: number;
  category: string | null;
}

function getProductInfo(product: Product): string {
  return `Product: ${product.name}, Price: ${product.price ?? 'N/A'}, Category: ${product.category ?? 'Unknown'}`;
}

위 예시에서 price는 옵셔널 타입이고, category는 string 또는 null일 수 있습니다. 널 병합 연산자를 사용하여 price와 category가 null 또는 undefined일 경우 기본값을 설정했습니다.

이전에 다양한 방법으로 null과 undefined를 다루는 방법을 설명해 드렸는데요, 좀 더 심층적으로 알아보고 싶은 부분이 있으신가요?

혹시 다음과 같은 부분에 대해 더 자세히 알고 싶으신가요?

  • 더 복잡한 타입과의 조합: 인터페이스, 클래스, 제네릭과 함께 null과 undefined를 사용하는 방법
  • 고급 타입 활용: never, unknown 타입과의 조합
  • tsconfig.json 설정: strictNullChecks 외에 다른 옵션을 이용한 설정
  • **nullish coalescing operator (??)와 optional chaining (?.)**의 활용
  • 함수 오버로드와 null, undefined
  • React, Angular 등 프레임워크에서의 null, undefined 처리

아니라면, 다음과 같은 예시를 통해 다른 관점에서 null과 undefined를 살펴볼 수 있습니다.

1. 인터페이스와 null, undefined

interface Person {
  name: string;
  age?: number; // age는 optional
  address: {
    city: string;
    zipCode: number | null; // zipCode는 number 또는 null
  };
}

위 예시처럼 인터페이스 내에서도 null과 undefined를 자유롭게 사용할 수 있습니다.

2. 제네릭과 null, undefined

function getLength<T>(value: T | null | undefined): number {
  if (value == null) {
    return 0;
  }
  return value.length;
}

제네릭을 사용하여 다양한 타입의 값을 받아 길이를 구하는 함수를 만들 수 있습니다.

3. nullish coalescing operator (??)와 optional chaining (?.)

const person: Person = { name: 'Alice', address: { city: 'Seoul' } };
const zipCode = person.address?.zipCode ?? 'Unknown';

optional chaining과 nullish coalescing operator를 함께 사용하여 안전하게 값에 접근하고 기본값을 설정할 수 있습니다.

4. tsconfig.json 설정

{
  "compilerOptions": {
    "strictNullChecks": true, // null과 undefined를 엄격하게 검사
    "noImplicitAny": true, // any 타입을 사용하지 않도록 강제
    // ... 다른 설정들
  }
}

tsconfig.json 파일에서 다양한 옵션을 설정하여 타입스크립트 컴파일러의 동작을 조절할 수 있습니다.

 

옵셔널 체이닝(Optional Chaining)

**옵셔널 체이닝(Optional Chaining)**은 ?. 연산자를 사용하여 객체의 프로퍼티에 접근할 때, 해당 프로퍼티가 존재하지 않거나 null 또는 undefined인 경우 에러 없이 undefined를 반환하는 기능입니다. 이를 통해 중첩된 객체의 프로퍼티에 안전하게 접근할 수 있습니다.

예시:

const user = {
  address: {
    street: 'Main Street'
  }
};

// 옵셔널 체이닝 사용
const streetName = user?.address?.street; // 'Main Street'

// 옵셔널 체이닝을 사용하지 않으면 에러 발생
// const streetName = user.address.street; // 에러: address가 undefined일 수 있음

장점:

  • 안전한 접근: 존재하지 않을 수 있는 프로퍼티에 접근할 때 발생할 수 있는 에러를 방지합니다.
  • 코드 간결화: if 문 등을 사용하여 null 또는 undefined를 체크하는 코드를 줄여줍니다.
  • 가독성 향상: 코드를 더욱 간결하고 명확하게 만들어줍니다.

널 병합 연산자(Nullish Coalescing Operator)

**널 병합 연산자(Nullish Coalescing Operator)**는 ?? 연산자를 사용하여 값이 null 또는 undefined인 경우에만 오른쪽 피연산자의 값을 반환하는 연산자입니다.

예시:

const name = null;
const displayName = name ?? 'Anonymous'; // 'Anonymous'
 

장점:

  • 기본값 설정: 변수의 값이 null 또는 undefined일 때 기본값을 쉽게 설정할 수 있습니다.
  • falsey 값과의 구분: false, 0, '' 등의 falsey 값은 기본값으로 설정되지 않습니다.

타입스크립트의 null 안전성(Null Safety)

타입스크립트는 null과 undefined를 명확하게 구분하고, 이들을 안전하게 처리하기 위한 다양한 기능을 제공합니다.

  • 옵셔널 타입: ?를 사용하여 변수나 프로퍼티가 null 또는 undefined일 수 있음을 나타냅니다.
  • 널 체크: if 문이나 널 병합 연산자를 사용하여 null 또는 undefined 값을 확인합니다.
  • Non-null assertion: !를 사용하여 변수가 절대 null 또는 undefined가 아니라고 확신할 때 사용합니다. (주의: 오용하면 오류 발생 가능성이 있습니다.)
  • strictNullChecks 옵션: tsconfig.json 파일에서 strictNullChecks 옵션을 true로 설정하면 null과 undefined를 더욱 엄격하게 검사합니다.

타입스크립트의 null 안전성을 통해 얻을 수 있는 이점:

  • 런타임 에러 감소: null 또는 undefined 값을 잘못 사용하여 발생하는 런타임 에러를 미리 방지할 수 있습니다.
  • 코드 신뢰성 향상: 코드의 안정성을 높이고 예측 가능한 동작을 보장합니다.
  • 개발 생산성 향상: 타입스크립트의 강력한 타입 시스템을 통해 개발 과정에서 오류를 빠르게 발견하고 수정할 수 있습니다.

결론

옵셔널 체이닝, 널 병합 연산자, 타입스크립트의 null 안전성은 안전하고 효율적인 자바스크립트 개발을 위한 필수적인 기능입니다. 이러한 기능들을 적절히 활용하여 코드의 품질을 높이고 유지보수성을 향상시킬 수 있습니다.

728x90