상수 분리하면서 내가 작성한 AI 프롬포트

신희원·2025년 8월 5일
0

리액트에서 타입스크립트 사용하기

Exported on 2025. 8. 6. at 1시 29분 0초 GMT+9 from Cursor (1.3.9)


User

나는 리액트 초보고 너는 교수님이야. 너는 이해 못하는 나에게 이해할 수 있도록 설명해줘야해. 내가 products.ts에 Products 상수를 export했는데, App.tsx에서 ProductWithUI로 되어있는것을 상수를 import해서 치환해주려고 하는데 왜 typeof Products[number]를 써야 문법오류가 안나는지 궁금해. Products를 그대로 쓸 수 없는거야?


Cursor

좋은 질문이야! 이건 TypeScript의 타입 시스템을 이해하는 데 중요한 개념이야. 차근차근 설명해줄게.

이제 이해했어! 너의 질문에 대해 차근차근 설명해줄게.

1. Products를 그대로 쓰면 안 되는 이유

// ❌ 이렇게 하면 안 돼
const addProduct = useCallback(
  (newProduct: Omit<Products, 'id'>) => {  // 에러!
    // ...
  },
  [addNotification],
);

왜 안 될까?

  • Products배열이야. ProductWithUI[] 타입이지.
  • 함수 매개변수는 하나의 객체를 받아야 하는데, 배열 전체를 타입으로 지정하면 안 돼.

2. typeof Products[number]가 뭔가?

이건 TypeScript의 인덱스 접근 타입(Indexed Access Types)이야.

// Products 배열에서 하나의 요소 타입을 가져오는 방법
typeof Products[number]

분해해서 설명하면:

  • typeof Products: Products 변수의 타입 (ProductWithUI[])
  • [number]: 배열의 인덱스 접근자
  • typeof Products[number]: 배열에서 하나의 요소 타입 (ProductWithUI)

3. 다른 방법들도 있어

// 방법 1: typeof Products[number] (현재 사용 중)
const addProduct = useCallback(
  (newProduct: Omit<(typeof Products)[number], 'id'>) => {
    // ...
  },
  [addNotification],
);

// 방법 2: 직접 타입 사용
const addProduct = useCallback(
  (newProduct: Omit<ProductWithUI, 'id'>) => {
    // ...
  },
  [addNotification],
);

// 방법 3: 배열 타입에서 추출
type ProductType = (typeof Products)[number];
const addProduct = useCallback(
  (newProduct: Omit<ProductType, 'id'>) => {
    // ...
  },
  [addNotification],
);

4. 왜 typeof Products[number]를 썼을까?

장점:
1. 타입 동기화: Products 배열이 변경되면 자동으로 타입도 업데이트
2. 단일 진실 공급원: 타입 정의를 한 곳에서만 관리
3. 실수 방지: 배열과 타입이 일치하지 않는 실수 방지

5. 실제 예시로 이해해보자

// products.ts
export const Products: ProductWithUI[] = [
  {
    id: 'p1',
    name: '상품1',
    price: 10000,
    // ...
  },
  // ...
];

// App.tsx
const addProduct = useCallback(
  (newProduct: Omit<(typeof Products)[number], 'id'>) => {
    // newProduct는 이렇게 생겼어:
    // {
    //   name: string;
    //   price: number;
    //   stock: number;
    //   description?: string;
    //   isRecommended?: boolean;
    //   discounts: Discount[];
    // }
    // (id는 제외됨)
  },
  [addNotification],
);

6. 요약

  • Products는 배열이니까 직접 사용할 수 없어
  • typeof Products[number]는 배열에서 하나의 요소 타입을 가져오는 방법
  • 이렇게 하면 배열이 변경되어도 타입이 자동으로 맞춰져

이해됐어? 더 궁금한 게 있으면 언제든 물어봐! 😊

// ❌ 이렇게 하면 안 돼
const addProduct = useCallback(
  (newProduct: Omit<Products, 'id'>) => {  // 에러!
    // ...
  },
  [addNotification],
);
// Products 배열에서 하나의 요소 타입을 가져오는 방법
typeof Products[number]
// 방법 1: typeof Products[number] (현재 사용 중)
const addProduct = useCallback(
  (newProduct: Omit<(typeof Products)[number], 'id'>) => {
    // ...
  },
  [addNotification],
);

// 방법 2: 직접 타입 사용
const addProduct = useCallback(
  (newProduct: Omit<ProductWithUI, 'id'>) => {
    // ...
  },
  [addNotification],
);

// 방법 3: 배열 타입에서 추출
type ProductType = (typeof Products)[number];
const addProduct = useCallback(
  (newProduct: Omit<ProductType, 'id'>) => {
    // ...
  },
  [addNotification],
);
// products.ts
export const Products: ProductWithUI[] = [
  {
    id: 'p1',
    name: '상품1',
    price: 10000,
    // ...
  },
  // ...
];

// App.tsx
const addProduct = useCallback(
  (newProduct: Omit<(typeof Products)[number], 'id'>) => {
    // newProduct는 이렇게 생겼어:
    // {
    //   name: string;
    //   price: number;
    //   stock: number;
    //   description?: string;
    //   isRecommended?: boolean;
    //   discounts: Discount[];
    // }
    // (id는 제외됨)
  },
  [addNotification],
);
profile
프론트엔드 공부하는 개발자입니다.

0개의 댓글