Web-Frontend/React.js

[React.js] React에 Typescript 적용하기

서노리 2023. 3. 14. 21:48
반응형

Why Typescript?

타입스크립트는 자바스크립트에 타입을 부여한 언어로 다음 두 가지 관점에서 자바스크립트 코드를 개선하고 개발 생산성을 높일 수 있다.

  • 에러의 사전 방지
  • 코드 가이드 및 자동 완성
const sum = (a,b) => a+b;

위의 자바스크립트 코드는 a와 b를 입력받아  a + b의 값을 구하는 함수이지만, a와 b에 숫자가 아닌 문자열 등을 넘기더라도 오류를 띄우거나 하지 않고 심지어 존재하지 않는 프로퍼티를 읽더라도 undefined를 주고 넘어가는 등 에러의 사전 방지에 취약한 모습을 보인다.

 

const sum = (a:number, b:number) => a+b;
sum(1,2);

위와 같이 :를 이용하여 타입을 정의하는 방식을 Type Annotation이라고 한다. 이렇게 타입스크립트를 사용하여 인자의 타입을 지정해주면 해당 코드 실행 전에 a와 b의 타입을 검사하여 의도하지 않은 코드의 동작을 예방할 수 있다.  자바스크립트에서도 propTypes를 활용하여 타입을 검사할 수 있었지만, 이는 코드가 실행된 이후에 검사하는 방식으로 타입스크립트는 코드 실행 전에 타입을 검사하게된다. 이렇게 타입을 검사하여 문제가 없다면 평범한 자바스크립트문으로 컴파일하여 브라우저가 읽을 수 있게 된다.

 

또한 VSCode 등 개발 툴에서 변수의 타입을 미리 알고 있기 때문에 코드 가이드나 자동 완성 기능을 온전히 사용할 수 있어 개발 생산성이 높아진다는 장점이 있다.


리액트에 타입스크립트 설치하기

# 신규 프로젝트 생성 시 타입스크립트 사용
npx create-react-app {app-name} --template typescript
# 기존 프로젝트에 타입스크립트 사용
npm install --save typescript @types/node @types/react @types/react-dom @types/jest
 
# 자바스크립트 기반 라이브러리인 경우 `@types/styled-components`와 같이 추가로 DefinitelyTyped 설치
# .js 파일은 .tsx 파일로 확장자 변경 후 개발서버 재시작

props 설정하기

const Container = styled.div``;
 
function Circle({bgColor}) {
  return <Container />;
}

일반적인 자바스크립트 환경에서는 아무 문제 없이 넘어가겠지만 타입스크립트는 bgColor의 타입을 모르기 때문에 에러를 띄운다. 이런 경우 interface 키워드를 사용해 해당 컴포넌트의 props에 대한 타입을 정의하는 인터페이스를 만들어주어야 한다.

 

interface CircleProps {
  bgColor: string;
}
 
interface ContainerProps {
  bgColor: string;
}
 
const Container = styled.div<ContainerProps>`
  width: 300px;
  height: 300px;
  background-color: ${(props) => props.bgColor};
  border-radius: 50%;
`;
 
function Circle({ bgColor }: CircleProps) {
  return <Container bgColor={bgColor} />;
}

 

Optional Props

컴포넌트에 반드시 필요하지 않은 props를 설정할 때는 물음표를 붙여주면 된다.

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

이렇게 선언하면 borderColor는 타입이 string | undefined가 되어 전달하지 않더라도 오류를 띄우지 않게된다.

 

※ nullish 병합 연산자

function Circle({ bgColor, borderColor }: CircleProps) {
  return <Container bgColor={bgColor} borderColor={borderColor ?? bgColor} />;
}

a ?? b와 같이 쓰이며 a가 null 또는 undefined라면 b, 아니라면 a라는 뜻으로 사용된다. 따라서 위 코드에서 borderColor를 입력받지 않았다면 borderColor로 bgColor 값을 사용하도록 할 수 있다.

 

※ default props 설정

function Circle({ bgColor, borderColor, text = 'Lorem Ipsum' }: CircleProps) {
  return (
    <Container bgColor={bgColor} borderColor={borderColor ?? bgColor}>
      {text}
    </Container>
  );
}

위와 같이 text = 'Lorem Ipsum'라고 설정하면 text를 입력받지 않았을 때의 기본값을 지정할 수 있다.


State

const [value, setValue] = useState(true);

타입스크립트에서는 state 초기값을 보고 타입을 유추하기 때문에 에러를 띄우지 않는다.

하지만 , state 값이 undefined나 null이 될 수 있거나, 여러 타입이 올 수 있다면 타입을 따로 지정해줄 수 있다.

 

const [value, setValue] = useState<number | null>(0);

 


Event

function App() {
  const [name, setName] = useState('');
  const onChange = (e) => {
    setName(e.target.value);
  };
 
  return (
    <form>
      <input type="text" value={name} onChange={onChange} />
      <button>확인</button>
    </form>
  );
}

 

 

위 코드는 onChange 함수에서 매개변수로 전달받는 이벤트의 타입을 명시해주지 않아 오류가 뜬다.

문서를 살펴보면 onChange는 Form Events이며 이벤트를 발생시킬 요소는 <HTMLInputElement>이다.

따라서 e 객체의 타입을 다음과 같이 지정해주어야 한다.

 

function App() {
  const [name, setName] = useState('');
  const onChange = (e: React.FormEvent<HTMLInputElement>) => {
    setName(e.currentTarget.value);
  };

 


Theme

styled component 등 자바스크립트 라이브러리는 타입이 정의되어 있지 않기 때문에 타입스크립트 환경에서 에러가 발생한다. 따라서 declaration 파일을 통해 타입스크립트에게 특정 라이브러리의 모양을 설명해주어야한다.

 

/* styled.d.ts */
 
// import original module declarations
import 'styled-components';
 
// and extend them!
declare module 'styled-components' {
  export interface DefaultTheme {
    textColor: string;
	bgColor: string
  }
}

styled.d.ts란 이름의 declaration 파일을 생성하고 styled component의 DefaultTheme에게 인터페이스를 지정해준다.

 

/* theme.ts */
 
import { DefaultTheme } from 'styled-components';
 
export const lightTheme: DefaultTheme = {
  textColor: '#000',
  bgColor: '#fff'
};
 
export const darkTheme: DefaultTheme = {
  textColor: '#fff',
  bgColor: '#000'
};
/* index.tsx */
 
//...
import { ThemeProvider } from 'styled-components';
import { darkTheme } from './theme';
 
ReactDOM.render(
  <React.StrictMode>
    <ThemeProvider theme={darkTheme}>
      <App />
    </ThemeProvider>
  </React.StrictMode>,
  document.getElementById('root')
);

 

반응형

'Web-Frontend > React.js' 카테고리의 다른 글

[React.js] Recoil - atom  (0) 2023.03.28
[React.js] React Query  (0) 2023.03.22
[React.js] Styled Component  (0) 2023.03.06
[React.js] React Router  (0) 2023.01.24
[React.js] SPA vs MPA  (0) 2023.01.24