행복을 담는 블로그

[React + TS] React에서 Typescript 사용하는 방법 알아보기 (2) 본문

FrontEnd/React

[React + TS] React에서 Typescript 사용하는 방법 알아보기 (2)

hyun0zin 2024. 3. 8. 21:14

5. Passing Props

예시 1) props로 {count}를 넘겨줄 때, type을 함께 지정해준다.
{count} : {count : string}

import { useState } from "react";

function Parent() {
  const [count, setCount] = useState("");
  return <Child count={count}></Child>;
}

function Child({ count }: {count: string) {
  return <div>{count}</div>;
}

export default Parent;

예시 2)

import { useState } from "react";

function Parent(){...}

type Props = {
  count: string;
};

function Child({ count }: Props) {
  return <div>{count}</div>;
}

export default Parent;

▶️ type을 위로 분리하여 선언하고, 선언한 타입을 컴포넌트에서 props으로 받을 수 있다.



props로 값을 넘겨주는 경우, 어떤 타입인지 알 수 없을 때,

: 마우스 hover 하면 어떤 타입의 값인지 확인 할 수 있다.

ex)

import { useState } from "react";

type Todo = {
  id: string;
  isDone: boolean;
};

// 부모 컴포넌트
function App() {
  const [todos, setTodos] = useState<Todo[]>([]);
  return (
    <>
      {todos.map(({ id }) => (
        <Todo key={id} id={id} setTodos={setTodos} />
      ))}
    </>
  );
}

// 자식 컴포넌트
function Todo({ id, setTodos } : { id: string; setTodos: React.Dispatch<React.SetStateAction<Todo[]>>;})
{
  const deleteTodo = () => {
    setTodos((prev) => prev.filter((todo) => todo.id !== id));
  };

  return <div onClick={deleteTodo}></div>;
}

export default App;

1️⃣ setTodos를 prop으로 넘겨줄 때, 어떤 타입인지 알기 어렵다. 이때 setTodos위에 마우스를 올려보면,

React.Dispatch<React.SetStateAction<Todo[]>> 타입임을 알 수 있다.

setTodos: React.Dispatch<React.SetStateAction<Todo[]>>;

2️⃣ setTodos : ()=> void : 반환값이 없는 함수를 콜백함수의 인자로 넘겨준다.

setTodos: (cb :(todo:Todo[])=> Todo[]) => void 

▶️ Todo[]를 받아서 Todo[]를 반환하는 콜백을 받은 다음, 아무것도 없는 void로 return 하는 함수를 setTodos에 넣어주는 것을 직관적으로 알아볼 수 있다.


3️⃣ 부모 컴포넌트에서 함수를 선언하고, 해당 함수만 넘겨 줄 때, 어떤 타입인지 마우스 호버로 확인해보자.

import { useState } from "react";

type Todo = {
  id: string;
  isDone: boolean;
};

// 부모 컴포넌트
function App() {
  const [todos, setTodos] = useState<Todo[]>([]);

  // 부모 컴포넌트에서 deleteTodo 함수 선언
  const deleteTodo = (id: string) => {
    const newTodos = todos.filter((todo) => todo.id === id);
    setTodos(newTodos);
  };
  return (
    <>
      {todos.map(({ id }) => (
        <Todo key={id} id={id} deleteTodo={deleteTodo} /> // props로 자식 컴포넌트로 전달
      ))}
    </>
  );
}

// 자식 컴포넌트
function Todo({ id, deleteTodo } : {id: string; deleteTodo: (id: string) => void;}) { // props로 받을 때, 타입 지정해주기
  const handleOnClick = () => {
    deleteTodo(id);
  };
  return <div onClick={handleOnClick}></div>;
}

export default App;



6. Children Props

예시 1) React.FC<Generic> : React 18버전 이전

type BaseType = {
  id: string;
};

//React 18버전 이전
const Child: React.FC<BaseType> = ({ id }) => {
  return <div>{id}</div>;
};

export function Parent() {
  return (
    <Child id="">
      <div>has children</div>
    </Child>
  );
}

▶️ "암묵적"으로 children으로 넘깁니다. 라는 의미를 가지고 있어 업데이트 이후 잘 사용되지 않음.


예시 2) PropsWithChildren

import { PropsWithChildren } from "react";

type BaseType = {
  id: string;
};

function Child({ children }: PropsWithChildren<BaseType>) {
  return <div>{children}</div>;
}

export function Parent() {
  return <Child id=""></Child>;
}

▶️ prop으로 { children }: PropsWithChildren<BaseType>을 통해 명시적으로 넘겨준다.
하지만, 아무런 children이 들어가지 않더라도 error가 나지 않는다.


🚨 children? : optional하게 가진다.
ReactNode와 undefined를 동시에 받는다 = children을 아무것도 넣지 않았을 때, 오류를 뱉지 않는다.


예시 3) type StrictChildren<T> = T & { children: ReactNode };

optional이 아닌 children에 ReactNode가 들어가도록, 엄격하게 type을 설정해준다.

import { ReactNode } from "react";

type BaseType = {
  id: string;
};

type StrictChildren<T> = T & { children: ReactNode };

function Child({ children }: StrictChildren<BaseType>) {
  return <div>{children}</div>;
}

export function Parent() {
  return (
    <Child id="">
      <div>chlidren</div>
    </Child>
  );
}



7. Utility Type : Omit / Pick

// Person Component 

// PersonProps에 5개의 속성을 가지고 있음
export type PersonProps = {
  id: string;
  description: string;
  address: string;
  age: number;
  profile: string;
};

export const PersonComponent = ({
  id,
  description,
  address,
  age,
  profile,
}: PersonProps) => {
  return (
    <>
      <PersonChildComponent>
        <div>{id}</div>
      </PersonChildComponent>
      <ProfileComponent
        description={description}
        address={address}
        age={age}
        profile={profile}
      />
      <AddressComponent address={address} />
    </>
  );
};

// PersonChild Component
export const PersonChildComponent = ({ children }: PropsWithChildren) => {
  return <>{children}</>;
};

// Omit : child 컴포넌트에서 "id" 속성을 제외하고 props으로 받고 싶을 때,
type OmitType = Omit<PersonProps, "id">;

export const ProfileComponent = ({
  description,
  address,
  age,
  profile,
}: OmitType) => {
  return <></>;
};

// Pick : child 컴포넌트에서 "address" 속성"만" props으로 받고 싶을 때,
type PickType = Pick<PersonProps, "address">;

export const AddressComponent = ({ address }: PickType) => {
  return <></>;
};

1) Omit : 특정 속성만 props에서 제외하고 싶을 때 사용

type OmitType = Omit<PersonProps, "id">;

2) Pick : 특정 속성만 props으로 받고 싶을 때 사용

type PickType = Pick<PersonProps, "address">;