[React] typescript 정리

sjoleee·2022년 7월 13일
1
post-custom-banner


타입스크립트는 자바스크립트의 확장판
에러 방지와 자동완성(생산성 향상)의 이점을 가진다.
아직 협업 경험이 없는데, 협업에서의 문제를 줄여줄 수 있다고 하더라!

props를 주고받을때 typing하는 방법

function App() {
  return (
    <div>
      <Box bgColor="blue" />
      <Box bgColor="red" />
    </div>
  );
}

파란 네모와 빨간 네모를 그리고 싶어서 Box 컴포넌트에 각각 색을 넘겨주었다.
Box에서 bgColor을 받아보자.

function Box({bgColor}) {
  return <Container />;
}

bgColor라는 prop을 받고싶은데... 타입스크립트 환경에서는 에러가 발생한다.
bgColor의 타입이 지정되지 않았기 때문이다.
우리는 interface를 사용해서 Box 컴포넌트가 받을 props의 타입을 지정해줄 수 있다.

interface BoxProps {
  bgColor: string;
}

function Box({bgColor}: BoxProps) {
  return <Container />;
}

이렇게 BoxProps라는 interface를 통해 Box가 받는 props의 타입을 지정해주면 자동완성도 되고 아주 편해진다. 하하

이제 Box에서 Container로 bgColor를 넘겨주자.

function Box({bgColor}: CircleProps) {
  return <Container bgColor={bgColor} />;
}
const Container = styled.div`
width: 100px;
heifht: 100px;
background-color: ${(props) => props.bgColor}
`

이렇게 쓰면 될 것 같지만 안된다.
Container 컴포넌트에서 bgColor를 사용하려면 또 타입을 지정해줘야한다.
마찬가지로 interface를 사용하자.

interface ContainerProps {
  bgColor: string;
}

const Container = styled.div<ContainerProps>`
width: 100px;
height: 100px;
background-color: ${(props) => props.bgColor}
`

완성!
합치면 이렇게 된다.

interface ContainerProps {
  bgColor: string;
}

const Container = styled.div<ContainerProps>`
width: 100px;
height: 100px;
background-color: ${(props) => props.bgColor}
`

interface BoxProps {
  bgColor: string;
}

function Box({bgColor}: BoxProps) {
  return <Container bgColor={bgColor}/>;
}

이렇게 interface를 사용해서 props를 전달할 수 있다.

optional props

interface를 사용하면서 이런 생각이 들 수 있다.
'박스 두개 중에 한개만 테두리를 넣고 싶은데, borderColor를 양쪽에 다 넘겨줘야지만 에러가 안나네?'
그러니까... 특정 props는 필수가 아니라 선택으로 넣고 싶을 수도 있지 않나?

function App() {
  return (
    <div>
      <Box bgColor="blue" />
      <Box bgColor="red" borderColor="green" />
    </div>
  );
}
interface BoxProps {
  bgColor: string;
  borderColor: string;
}

function Box({bgColor, borderColor}: BoxProps) {
  return <Container bgColor={bgColor} borderColor={borderColor} />;
}

이렇게 아까 bgColor때와 동일하게 하면 에러가 발생한다.
파란 박스에는 borderColor가 없기 때문.

borderColor를 필수가 아닌 선택으로 하고싶다면 ?를 사용하자.

interface BoxProps {
  bgColor: string;
  borderColor?: string;
}

?하나면 선택이 된다.
그리고 a ?? b를 사용하면 '있으면 a를, 없으면 b를'이라는 표현도 가능하다.

function Box({bgColor, borderColor}: BoxProps) {
  return <Container 
    bgColor={bgColor} 
    borderColor={borderColor ?? bgColor}
    //borderColor가 있으면 borderColor를 사용하고, 없으면 bgColor를 사용해라
  />;
}

혹 prop에 기본값을 설정하고 싶다면 아래와 같이 사용하면 된다.

interface BoxProps {
  bgColor: string;
  borderColor?: string;
}

function Box({bgColor, borderColor="red"}: BoxProps) {
  return <Container 
    bgColor={bgColor} 
    borderColor={borderColor}
  />;
}

이제 borderColor는 기본값이 red다.
만약 borderColor를 지정해주지 않는다면, 자동으로 빨간색이 된다.

state의 type을 지정할 수 있음

const [state, setState] = useState(1);
//초기값으로 1을 넣으면 자동으로 state의 타입이 number이 된다.
//즉, 초기값의 타입이 state의 타입이 된다.

초기값의 타입과 다른 값이 들어갈 일은 잘 없겠지만...
혹시나 state에 들어갈 값이 한 타입이 아니라면?

const [state, setState] = useState<string | number>(0);
  setState(2);
  setState("hi");

이렇게하면 state에 string과 number 두 타입 모두 들어갈 수 있게 된다.

typescript 환경에서 form을 만드는 방법

function App() {
  const [username, setUsername] = useState("");
  //username에 유저가 입력한 값이 들어옴
  const onChange = (event: React.FormEvent<HTMLInputElement>) => {
    const {
      currentTarget: { value },
    } = event;
    //구조분해할당. event.currentTarget.value랑 같은 말
    setUsername(value);
  };
  const onSubmit = (event: React.FormEvent<HTMLFormElement>) => {
    event.preventDefault();
    console.log(`hi ${username}`);
  };
  return (
    <div>
      <form onSubmit={onSubmit}>
        <input
          value={username}
          onChange={onChange}
          placeholder="id"
          type="text"
        ></input>
        <button>log in</button>
      </form>
    </div>
  );
}

typescript 환경에서 theme 설정하기

먼저, styled.d.ts를 생성한다.

import "styled-components";

declare module "styled-components" {
  export interface DefaultTheme {
    textColor: string;
    bgColor: string;
  }
}

그리고 theme.ts를 생성해서 dark/light theme를 만든다.

import { DefaultTheme } from "styled-components";

export const darkTheme: DefaultTheme = {
  textColor: "white",
  bgColor: "black",
};

export const lightTheme: DefaultTheme = {
  textColor: "black",
  bgColor: "white",
};

index.tsx에서 ThemeProvider 설정하기

import { darkTheme, lightTheme } from "./theme";

const root = ReactDOM.createRoot(
  document.getElementById("root") as HTMLElement
);
root.render(
  <React.StrictMode>
    <App />
    <ThemeProvider theme={lightTheme}>
      <App />
    </ThemeProvider>
  </React.StrictMode>
);
profile
상조의 개발일지
post-custom-banner

0개의 댓글