[TypeScript] React에서 적용하기

jungmin Lee·2023년 9월 1일
1

TypeScript를 직접 프로젝트에 적용해보니 아직 정리가 되지 않을 부분들도 있었고 쉽게 적용되지가 않았다. React에서 TypeScript를 적용할때 많이 쓰는 타입들과 사용방법에 대해서 정리해보자!

기본 타입 & 객체와 인터페이스

기본 타입
number, string, boolean: 기본 데이터 타입으로 상태(State),Props의 속성의 타입으로 정의할 때 사용한다.
null, undefined, void: 값이 없음을 나타낼때 사용하는 타입이다.


객체와 인터페이스
interface: 객체의 구조를 타입으로 정의하는데 사용한다.
type: 객체 타입을 정의하는데 사용되며, 유니온, 인터섹션 타입 정의에 사용한다.

interface Student {
  id: number;
  name: string;
}

// 유니온 타입: 여러 타입 중 하나가 될 수 있는 값을 나타냄
type User {
  id: number;
  name: string;
}

type Student {
  id: number;
  Subject: string;
}

type UserInfo = User | Student

// 인터섹션 타입: 여러 타입을 결합하여 하나의 타입으로 만들 때 사용
type User {
  id: number;
  name: string;
}

type UserProfile {
  age: number;
  image: string;
}

type User & UserProfile

함수 타입

함수의 매개변수와 반환값에 대한 타입을 정의할 때 사용한다.

type Calculator = (a: number, b: number) => number;

const add: Calculator = (a, b) => a + b;

// 선택적 매개변수: 선택적으로 매개변수를 받을 수 있으며 기본값을 설정할 수 있다.
type Greetings = (name: string, greeting?: string) => string;

const greet: GreetingFunction = (name, greeting = "Hello") => {
  return `${greeting}, ${name}!`;
};

// 오버로드된 함수 타입: 하나의 함수에 대해 다른 함수 형태를 가질 수 있다. 함수가 다른 매개변수 형식 또는 반환값 형식에 따라 다르게 동작할 때 사용된다.
type PrintValue = {
  (value: number): void;
  (value: string): void; 
};

const printValue: PrintValue = (value) => {
  console.log(value);
};

printValue(123);  
printValue("Hello World"); 

이벤트 핸들러 타입

React 컴포넌트의 이벤트 핸들러를 타입으로 정의할 때 사용한다.
React.MouseEvent, React.KeyboardEvent, React.FormEvent, React.EventHandler가 있다.

// React.MouseEvent 타입: 마우스 이벤트를 다룰 때 사용하며, 주로 onClick, onMouseDown, onMouseUp, onMouseMove 등의 이벤트에 사용된다.
type MouseClickHandler = (event: React.MouseEvent<HTMLButtonElement>) => void;

const handleClick: MouseClickHandler = (event) => {
  console.log(event.clientX, event.clientY);
};

<button onClick={handleClick}>Click Me</button>;

// React.KeyboardEvent 타입: 키보드 이벤트를 다룰 때 사용되며, onKeyDown, onKeyUp, onKeyPress 등의 이벤트에 사용된다.
type KeyPressHandler = (event: React.KeyboardEvent<HTMLInputElement>) => void;

const handleKeyPress: KeyPressHandler = (event) => {
    if (event.key === 'Enter') {
    console.log('Enter key pressed!');
  }
};

<input type="text" onKeyPress={handleKeyPress} placeholder="텍스트를 입력해주세요" />;

//React.FormEvent 타입: 폼 요소에서 발생하는 이벤트를 다룰 때 사용되며, 주로 onSubmit, onChange 등에 사용된다.
type FormSubmitHandler = (event: React.FormEvent<HTMLFormElement>) => void;

export default function MyForm() {
  const [text, setText] = useState<string>('');

  const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
    setText(event.target.value);
  };

  const handleSubmit: FormSubmitHandler = (event) => {
    event.preventDefault();
    console.log('Form submitted', text); 
  };

  return (
    <form onSubmit={handleSubmit}>
      <input
        type="text"
        placeholder="텍스트를 입력해주세요"
        value={text}
        onChange={handleChange}
      />
      <button type="submit">Submit</button>
    </form>
  );
};

상태(State) 관리 타입

리덕스(Redux)와 같은 상태 관리 라이브러리에서 액션과 상태 타입을 정의할 때 사용할 수 있다.

Redux

// 액션(Action) 타입
const ADD_TODO = 'ADD_TODO';
const DELETE_TODO = 'DELETE_TODO';

// 액션 생성자(Action Creator)
function addTodo(text: string) {
  return {
    type: ADD_TODO,
    text,
  };
}

function deleteTodo(text: string) {
  return {
    type: DELETE_TODO,
    text,
  };
}

// 상태(State) 타입
interface User {
  id: number;
  name: string;
}

interface TodoState {
  todos: Todo[];
  user: User | null;
}

type TodoAction = {
  type: typeof ADD_TODO | typeof DELETE_TODO;
  text: string;
};

// 리듀서(Reducer)
const initialTodoState: TodoState = {
  todos: [],
  user: null,
};

function todosReducer(state: TodoState = initialTodoState, action: TodoAction): TodoState {
  switch (action.type) {
    case ADD_TODO:
      return {
        ...state,
        todos: [...state.todos, { text: action.text, completed: false }],
      };
    case DELETE_TODO:
      return {
        ...state,
        todos: state.todos.filter((todo) => todo.text !== action.text),
      };
    default:
      return state;
  }
}

Context API

import { createContext, useContext, useState } from 'react';

const TodoContext = createContext<Todo[]>([]);

const TodoProvider: React.FC = ({ children }) => {
  const [todos, setTodos] = useState<Todo[]>([]);
  return (
    <TodoContext.Provider value={todos}>
      {children}
    </TodoContext.Provider>
  );
};

ref와 DOM 요소 타입

ref를 사용하여 DOM 요소에 접근할 때, 해당 요소의 타입을 지정할 수 있다.

import React, { useRef } from 'react';

export default function MypageInput () {
  const inputRef = useRef<HTMLInputElement>(null);

  const focusInput = () => {
    if (inputRef.current) {
      inputRef.current.focus();
    }
  };

  return (
    <div>
      <input ref={inputRef} />
      <button onClick={focusInput}>Click Me!</button>
    </div>
  );
};

React.FC와 Props 타입

React.FC를 사용하여 컴포넌트의 함수 타입을 정의하고, Props 타입으로 컴포넌트의 속성 타입을 정의한다.

interface Props {
  name: string;
  age: number;
}

export default function UserContent ({ name, age }:Props) {
  return (
    <div>
      <p>Name: {name}</p>
      <p>Age: {age}</p>
    </div>
  );
};

React.ReactNode와 조건부 렌더링

컴포넌트 내에서 조건부로 렌더링할 때 사용하는 타입이다

interface ToggleDisplayProps {
  show: boolean;
  children: React.ReactNode;
}

export default function ToggleDisplay ({ show, children }:ToggleDisplayProps) {
  return show ? <div>{children}</div> : null;
};

라우팅과 URL 매개변수 타입

React Router와 함께 사용할 때 라우트와 URL 매개변수의 타입을 정의한다.

import { RouteComponentProps } from 'react-router-dom';

interface MatchParams {
id: string;
}

export default function UserProfile({ match }: RouteComponentProps) {
const userId = match.params.id;
// ...
}



profile
Leejungmin

0개의 댓글