조건부 렌더링은 UI에서 특정 조건에 따라 컴포넌트를 숨기거나 보이게 할 수 있어.

TypeScript에서는 **조건에 따라 타입을 좁히는 “타입 가드”**를 함께 사용하는 것이 핵심이야.


📘 예제 71: 타입 내 조건 분기

type User = {
  name: string;
  age?: number;
};

const UserInfo = ({ user }: { user: User }) => {
  return (
    <div>
      <p>이름: {user.name}</p>
      {user.age && <p>나이: {user.age}세</p>}
    </div>
  );
};

✅ user.age는 number | undefined이기 때문에 조건문에서 && 연산으로 undefined 여부를 체크해줘야 해.


📘 예제 72: 옵셔널 체이닝

type User = {
  name: string;
  profile?: {
    bio?: string;
  };
};

const Profile = ({ user }: { user: User }) => {
  return (
    <div>
      <h2>{user.name}</h2>
      <p>{user.profile?.bio ?? '소개 없음'}</p>
    </div>
  );
};

✅ 옵셔널 체이닝(?.)은 중첩된 객체 접근 시 undefined 오류 없이 안전하게 접근할 수 있어.

??는 nullish 병합 연산자, 즉 값이 null이나 undefined면 기본값을 사용해.


📘 예제 73: null 체크와 타입 좁히기

type Product = {
  id: number;
  name: string;
};

const ProductDetail = ({ product }: { product: Product | null }) => {
  if (!product) {
    return <p>상품 정보를 불러오는 중입니다...</p>;
  }

  return <h2>{product.name}</h2>;
};

✅ product가 null일 수 있기 때문에 렌더링 전에 null 체크를 해주면 그 이후부터는 TypeScript가 product를 Product로 자동 인식해.


📘 예제 74: 사용자 정의 타입 가드

type Dog = { kind: 'dog'; bark: () => void };
type Cat = { kind: 'cat'; meow: () => void };
type Animal = Dog | Cat;

const isDog = (animal: Animal): animal is Dog => {
  return animal.kind === 'dog';
};

const AnimalSound = ({ animal }: { animal: Animal }) => {
  if (isDog(animal)) {
    animal.bark();
    return <p>멍멍!</p>;
  } else {
    animal.meow();
    return <p>야옹~</p>;
  }
};

✅ animal is Dog처럼 타입을 좁히는 함수를 사용자 정의 타입 가드라고 해. 조건문 안에서 안전하게 bark를 사용할 수 있게 해줘.