[TIL] React + TypeScript

·2023년 12월 14일
0

TIL

목록 보기
56/85
post-thumbnail

TypeScript 시작하기

# yarn을 사용하는 경우
yarn create react-app my-app --template typescript

# npx를 사용하는 경우
npx create-react-app my-app --template typescript

함수에서 TypeScript 사용하기

함수의 파라미터와 리턴값이 있다면 그에 대한 타입을 지정해줘야한다.
객체를 파라미터로 받는 함수라면 객체 내 속성들에 대한 타입도 지정해줘야한다.
1

function sum(a: number, b: number): number {
  return a + b;
}

function objSum({ a, b }: { a: number; b: number }): string {
  return `${a + b}`;
}

2

// Type Aliases (타입 별칭)
type Player = {
   readonly name: Name,
    age?: Age  // ? 를 앞에 붙이면 optional
}

function playerMaker(name: string): Player{
     return {
         name
     }
}
// 화살표 함수
const playerMaker = (name:string) : Player => ({
    name
})

(JS 참고)
[화살표 함수 표현식]

const func = (x) => x * x;
// 간결한 본문 구문, 암시적 "반환"

간결한 본문 구문을 사용하여 return을 명시하지 않고 값을 리턴할 때 (params) => { object: literal } 을 사용하여 객체를 반환하면 예상대로 작동하지 않는다.
JS는 화살표 뒤에 오는 식이 왼쪽 중괄호가 아닌 경우에만 화살표 함수에 간결한 본문이 있는 것으로 간주한다.
이 문제를 해결하려면 객체를 괄호로 묶으면 된다.

const func = () => ({ foo: 1 });

비동기 함수에서 TypeScript 사용하기

type Person = { id: number; age: number; height: number };

async function getPerson(): Promise<Person[]> {
  const res = await fetch(`http://localhost:5008/people`);
  if (!res.ok) {
    throw new Error();
  }
  return res.json();
}

getPerson().then((res) => console.log(res[0]));

useState

state 같은 경우 초기값에 따라 타입을 추론한다
타입을 명시하고 초기값을 설정하지 않으면 undefined도 포함되는 것이다.

import { useState } from "react";

function App() {
  const [counter, setCounter] = useState<number>(1);
  const increment = () => {
    setCounter((prev) => prev++);
  };
  return <div onClick={increment}>{counter}</div>;
}

export default App;

Props

import { useState } from "react";

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

type Props = {
  count: string;
};

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

export default Parent;

Children Props

PropsWithChildren 사용

PropsWithChildren을 제네릭으로 사용하면 undefined와 children을 둘 다 받을 수 있는 상태가 된다.

import { PropsWithChildren } from "react";

type BaseType = {
  id: string;
};

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

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

제네릭에 BaseType 을 넣어주기만 하면 바로 children props를 사용할 수 있다
이렇게 쓰면 BaseType + Children 을 자동으로 생성해준다.
그러나 PropsWithChildren 도 한가지 문제점이 있다.
그것은 PropsWithChildren 이 children 을 옵셔널 하게 갖는 다는 점이다.
그러므로 우리가 children 을 넘기지 않아도 아무런 오류를 뱉지 않는다.

그래서 PropsWithChildren 조차 명시적이지 않다는 위험성이 있어서
엄격하게 사용할 수 있는 방법도 있다.

엄격한 children 사용

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>
  );
}

Utility Type

import {
  AddressComponent,
  PersonChildComponent,
  ProfileComponent,
} from "./UtilityTypeChildren";

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} />
    </>
  );
};
import { PropsWithChildren, ReactNode } from "react";
import { PersonProps } from "./UtilityType";

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

type OmitType = Omit<PersonProps, "id">; // ⭐️

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

type PickType = Pick<PersonProps, "address">; // ⭐️

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

✅ Pick<T, K> 타입이란?

  • Pick<T, K> 유틸리티 타입은 타입 T에서 K 속성들만 선택하여 새로운 타입을 만든다.
  • 이를 통해 타입의 일부 속성만을 포함하는 객체를 쉽게 생성할 수 있다.

✅ Omit<T, K> 타입이란?

  • Omit<T, K> 유틸리티 타입은 타입 T에서 K 속성들만 제외한 새로운 타입을 만든다!
  • Pick<T, K> 유틸리티 타입과는 반대의 동작
  • 이를 통해 기존 타입에서 특정 속성을 제거한 새로운 타입을 쉽게 생성할 수 있다.

그 밖에 Partial<T> Required<T> Readonly<T> 등 다양한 유틸리티 타입이 있다.

Event Handler

이벤트를 사용할 때는 이벤트 핸들러의 타입을 지정해주면 된다.

import { useState, MouseEvent } from "react";

function App() {
  const [counter, setCounter] = useState<number>(1);
  const eventHandler = (e: MouseEvent<HTMLDivElement>) => {};
  return <div onClick={eventHandler}>{counter}</div>;
}

export default App;
profile
느리더라도 조금씩, 꾸준히

0개의 댓글