코딩에 진심인 사람을 위해 준비한 리액트 타입스크립트 | 실제 회사에서 쓰는 레벨 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로 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;
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>