타입스크립트와 React 연동 – props, state에 타입 지정하기 (19강)
타입스크립트와 React 연동 – props, state에 타입 지정하기 (19강)
**React**와 **TypeScript**를 함께 사용하면, **강력한 타입 시스템**을 통해 코드의 안정성을 높이고 **버그를 예방**할 수 있습니다. React의 **props**와 **state**에 타입을 지정하는 것은 React 컴포넌트를 더욱 안전하고 효율적으로 만드는 핵심 기술입니다. 이번 강의에서는 **TypeScript**와 **React**를 연동하여 **props**와 **state**에 타입을 지정하는 방법을 알아보겠습니다.
TypeScript와 React: 왜 연동해야 할까?
**React**는 UI를 구성하는 데 유용한 라이브러리지만, **동적**이고 **변화가 많은** 데이터를 처리하는 과정에서 **타입 안정성**을 보장하지 못할 수 있습니다. **TypeScript**는 이러한 문제를 해결하는 데 도움을 주며, **타입 정의**를 통해 **컴파일 타임에 오류를 잡을 수** 있도록 합니다. **TypeScript**를 React에 연동하면 **props**, **state**, **함수 매개변수**에 타입을 지정하여 코드를 더욱 **안전하고 명확하게** 만들 수 있습니다.
1. React 컴포넌트에서 props 타입 지정하기
React에서 **props**는 부모 컴포넌트로부터 자식 컴포넌트로 전달되는 데이터입니다. **TypeScript**를 사용하면, 이 **props**에 타입을 명시하여 **데이터의 형태**를 강제할 수 있습니다. 이를 통해 **props로 전달되는 데이터의 형식**을 정확하게 정의하고, 잘못된 데이터 전달을 방지할 수 있습니다.
1.1 기본적인 props 타입 지정
**TypeScript**에서 React 컴포넌트의 props에 타입을 지정하려면, **인터페이스**나 **타입 앨리어스**를 사용합니다. `React.FC`(Functional Component) 타입을 사용할 수도 있지만, 더 명확하게 타입을 지정하려면 **인터페이스**를 사용하는 것이 좋습니다.
interface MyComponentProps {
name: string;
age: number;
}
const MyComponent: React.FC = ({ name, age }) => {
return (
{name}
Age: {age}
);
};
export default MyComponent;
위 예제에서 **MyComponentProps** 인터페이스를 통해 **name**과 **age** props의 타입을 각각 **string**과 **number**로 지정하였습니다. 이를 통해 **props**가 예상한 타입으로 전달되지 않으면 컴파일 타임에서 오류를 발생시켜 잘못된 데이터 전달을 방지할 수 있습니다.
1.2 선택적 props와 기본값 설정
때때로 **props**는 필수가 아닐 수도 있습니다. 이런 경우 **`?`**를 사용하여 **선택적**으로 만들 수 있습니다. 또한 기본값을 설정하려면 **디폴트 값을 할당**하거나, **`defaultProps`**를 활용할 수 있습니다.
interface MyComponentProps {
name: string;
age?: number; // 선택적 props
}
const MyComponent: React.FC = ({ name, age = 30 }) => {
return (
{name}
Age: {age}
);
};
export default MyComponent;
위 예제에서 **age**는 **선택적(props?)**로 정의되었으며, 기본값으로 **30**을 설정하여 **age**가 전달되지 않았을 때 **30**이 자동으로 할당됩니다.
2. React 컴포넌트에서 state 타입 지정하기
React 컴포넌트에서 **state**는 컴포넌트 내부에서 관리되는 데이터로, **setState**를 통해 값을 업데이트합니다. **TypeScript**에서는 state의 타입을 명확히 지정하여, 예상치 못한 데이터 타입이 들어가는 것을 방지할 수 있습니다.
2.1 기본적인 state 타입 지정
React에서 **useState**를 사용할 때, **타입을 명시적으로 지정**할 수 있습니다. **useState**는 제네릭을 사용하여 **state**가 가질 수 있는 타입을 정의할 수 있습니다.
import { useState } from "react";
const Counter: React.FC = () => {
const [count, setCount] = useState(0); // state 타입 지정
const increment = () => setCount(count + 1);
const decrement = () => setCount(count - 1);
return (
Count: {count}
);
};
export default Counter;
위 예제에서 **useState
2.2 객체 상태와 타입 지정
**state**가 객체일 경우, 해당 객체의 타입을 **인터페이스**나 **타입 앨리어스**로 정의해주는 것이 좋습니다. 이렇게 하면 **state** 내 속성에 대해서도 타입 체크가 이루어집니다.
interface CounterState {
count: number;
step: number;
}
const Counter: React.FC = () => {
const [state, setState] = useState({ count: 0, step: 1 });
const increment = () => setState({ ...state, count: state.count + state.step });
const decrement = () => setState({ ...state, count: state.count - state.step });
return (
Count: {state.count}
);
};
export default Counter;
이 예제에서는 **CounterState** 인터페이스를 사용하여 **state**가 **count**와 **step** 속성을 가짐을 명시적으로 지정했습니다. 이를 통해 **state** 객체 내에서 속성 타입을 정확하게 정의하고, 컴파일 타임에 타입 오류를 발견할 수 있습니다.
3. props와 state 타입을 동시에 지정하기
React 컴포넌트에서 **props**와 **state**는 함께 사용될 때가 많습니다. **TypeScript**에서는 props와 state의 타입을 각각 정의하고, 이를 컴포넌트에서 적절히 활용할 수 있습니다.
interface MyComponentProps {
title: string;
}
interface MyComponentState {
count: number;
}
class MyComponent extends React.Component {
constructor(props: MyComponentProps) {
super(props);
this.state = {
count: 0,
};
}
increment = () => this.setState({ count: this.state.count + 1 });
render() {
const { title } = this.props;
const { count } = this.state;
return (
{title}
Count: {count}
);
}
}
export default MyComponent;
이 예제에서는 **class 컴포넌트**를 사용하여 **props**와 **state**의 타입을 각각 **MyComponentProps**와 **MyComponentState**로 지정하였습니다. 이를 통해 클래스 컴포넌트에서 **props**와 **state**를 안전하게 다룰 수 있습니다.
결론
**TypeScript**와 **React**를 함께 사용하면, **props**와 **state**에 타입을 지정함으로써 컴포넌트를 더욱 안전하고 예측 가능하게 만들 수 있습니다. **props**의 타입을 지정하면, **잘못된 데이터 전달**을 방지하고, **state**의 타입을 지정하면 예상치 못한 값이 들어가는 것을 막을 수 있습니다. **TypeScript**를 활용하여 **React 컴포넌트**의 **타입 안정성**을 높이고, 버그를 예방할 수 있습니다.