리액트에 타입스크립트 적용해보기

posinity·2023년 9월 3일
0

Typescript

목록 보기
8/8

코딩에 진심인 사람을 위해 준비한 리액트 타입스크립트 | 실제 회사에서 쓰는 레벨 ver 영상을 정리한 글입니다.

데이터 타입 지정하기

아래같은 데이터가 있을 때 타입을 지정하는 방법을 알아보자

const data = {
  name: "gildong",
  category: "developer",
  address: {
    city: "seoul",
    detail: "dong",
  },
  menu: [
    { name: "pasta", price: 20000 },
    { name: "pizza", price: 30000 },
  ],
};

타입을 지정할 땐 type과 interface가 있음.
두개의 큰 차이는 없다.

data를 가리키면 아래처럼 설명이 나오는데, 이것을 복사해서 사용하면 편하다.

타입 지정 파일 만들기

src폴더 안에 Models 폴더를 만들고, 타입을 적어둘 파일을 하나 생성한다.
나는 Data.ts 파일을 만들었다

// Data.ts

export type Data = {
  name: string;
    category: string;
    address: {
        city: string;
        detail: string;
    };
    menu: {
        name: string;
        price: number;
    }[];
};

데이터의 타입을 위와 같이 정해준다.
export해서 다른 곳에서 사용하기 편하도록 한다.

타입을 따로 지정해줄 수도 있다.

export type Data = {
  name: string;
  category: string;
  address: Address;
  menu: Menu[];
};

export type Address = {
  city: string;
  detail: string;
};

export type Menu = {
  name: string;
  price: number;
};

이렇게 따로 지정해준다면, menu, address 타입 지정을 다른 곳에서도 사용할 수 있다.

만든 타입 적용하기

다시 app.tsx로 돌아와서,
상단에 만들어놓은 타입을 import하고,
: Data 이런식으로 적용한다

import { Data } from "./Models/data";

const data: Data = {
  name: "gildong",
  category: "developer",
  address: {
    city: "seoul",
    detail: "dong",
  },
  menu: [
    { name: "pasta", price: 20000 },
    { name: "pizza", price: 30000 },
  ],
};

props 타입 적용하기

만약 자식 컴포넌트의 props로 data를 내려보내고 싶다면?
기존과 똑같이 data를 내려보낸 후,

function App() {
  return (
    <>
      <Store info={data} />
    </>
  );
}

내가 지정해놓은 data타입과 props의 타입이 동일하므로,
만들어놓은 타입 지정을 불러온 후,
props에 지정해준다.

이번에는 interface를 사용했다.

/// Store.tsx

import { Data } from "../Models/data";

interface DataProps { //props의 타입 지정
  info: Data;
}

const Store = ({ info }: DataProps) => { //props의 타입 지정
  return <div>{info.name}</div>;
};

export default Store;

useState에 타입 적용하기

data를 useState로 관리하고 싶다면?
<> 제너릭 문법으로 타입을 지정해주는데,
제너릭 문법은 useState를 부르는 순간에 타입을 지정해주고 싶을 때 사용한다.
위에 지정해준 Data 타입과 동일하므로 Data를 넣어준다.

function App() {
  const [myrestaurant, setMyrestaurant] = useState<Data>(data);
  return (
    <>
      <Store info={myrestaurant} />
    </>
  );
}

함수에 타입 지정하기

data에서 address 데이터를 바꾸는 함수를 만든다고 하자.

const changeAddress = (address) => {
    setMyrestaurant({...myrestaurant, address: address})
  }

인자로 받는 address의 타입을 지정해줘야 하는데,
아까 만든 Address 타입을 불러와 지정해주면 된다.

import { Address, Data } from "./Models/data";
...
const changeAddress = (address:Address) => {
    setMyrestaurant({...myrestaurant, address: address})
  }

props로 함수를 보낼 때는?

/// Store.tsx

import { Address, Data } from "../Models/data";

interface DataProps {
  info: Data;
  changeAddress(address: Address): void;
}

마찬가지로 인자의 타입을 지정해준 후 : void를 추가해준다
리턴타입이 없는 함수의 타입을 지정해줄 때 위와 같이 씀

만약 리턴타입이 있는 함수의 타입을 지정해줄 때는

changeAddress(address: Address): boolean; 

이런식으로 지정해주면 된다

타입 확장하기

props로 기존에 설정해준 타입과, 새로운 함수를 넘기고 싶을 때
extends 문법을 사용하면 된다.

const showBestMenu = (name: string) => {
    return name;
  }; // 이 함수를 새로 만들어서 넘기고 싶다

  return (
    <>
      <Store info={myrestaurant} changeAddress={changeAddress} />
      <BestMenu name="불고기피자" price={20000} showBestMenu={showBestMenu} />
    </>
  );

이름과 가격은 이미 타입을 지정해준 것이 있으니 불러오고
추가로 새로 만든 showBestMenu 함수의 타입만 지정해준다.

/// BestMenu.tsx

import { Menu } from "../Models/data";

interface MenuProps extends Menu {
  showBestMenu(name: string): string;
}

const BestMenu = ({ name, price, showBestMenu }: MenuProps) => {
  return <div>{name}</div>;
};

export default BestMenu;

type은 아래처럼 작성한다

type MenuProps = Menu & {
  showBestMenu(name: string): string;
};

타입에서 특정 지정한 타입 중 하나를 빼고 싶을 때

지정해준 Data 타입에서 address를 빼고 싶을 때
Omit을 사용하면 된다.
Omit<타입지정이름, 뺄 타입 키>

export type Data = {
  name: string;
  category: string;
  address: Address;
  menu: Menu[];
};

export type DataWithoutAddress = Omit<Data, "address">;

props로 내려보내는 것 중에 일부 값만 빼서 내려보내는 경우

<BestMenu name="불고기피자" showBestMenu={showBestMenu} />

Menu 타입은 price값이 지정되어있기 때문에
BestMenu 컴포넌트는 오류를 낸다.
아래와 같이 적어준다.

/// BestMenu.tsx

interface MenuProps extends Omit<Menu, "price"> {
  showBestMenu(name: string): string;
}

옵셔널 체이닝으로도 가능하다.

export type Data = {
  name: string;
  category: string;
  address?: Address;
  menu: Menu[];
};

다만, 옵셔널 체이닝으로 사용할 경우는, Data에서 address가 반드시 있어야 할 상황일 때, 없어도 ok가 되버리므로 사용에 주의가 필요하다

타입에서 특정 키값만 선택하고 싶을 때

Pick을 써준다.

export type Data = {
  name: string;
  category: string;
  address: Address;
  menu: Menu[];
};

export type DataPickName = Pick<Data, "name">;

+) 데이터를 받을 때

데이터를 받을 때, data에 다양한 종류의 타입이 들어오는 경우가 있음
그럴 때 제너럴 T를 사용한다

export type ApiResponse<T> = {
  data: T[];
  totalPage: number;
  page: number;
};

export type StoreResponse = ApiResponse<Data>
export type MenuResponse = ApiResponse<Menu>
profile
문제를 해결하고 가치를 제공합니다

0개의 댓글