231121 TIL

thisisyjin·2023년 11월 20일
0

TIL 📝

목록 보기
98/113

React.js + TS

  • React 프로젝트 -> TS + React로 변경

Dependencies 설치

$ npm install -D typescript @types/react @types/react-dom

그 외

  • vite.config.js -> ts로 수정
  • tsconfig.node.json 파일 생성
  • src/vite-env.d.ts

참고 - vite 프로젝트 생성 시 Typescript 선택 시 자동으로 생성됨

  • index.html에서 main.jsx -> main.tsx로 수정
  • main.jsx -> main.tsx 수정
ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(<App />);
  • tsconfig.json에서 allow.js을 true로 수정
    자바스크립트 파일을 사용할 수 있게 해줄 것인지 설정

types 설정

/src/types 폴더 생성해서 타입들만 모아놓기 (.ts)

export interface PokemonData {
  count: number;
  next: string | null;
  previous: string | null;
  results: PokemonNameAndUrl[];
}

export interface PokemonNameAndUrl {
  name: string;
  url: string;
}

  1. State에 타입 지정하기
const [allPokemons, setAllPokemons] = useState([]); // error
const [allPokemons, setAllPokemons] = <PokemonNameAndUrl[]>useState([]); // OK
  • allPokemons라는 state가 PokemonNameAndUrl이라는 타입을 가진다.
  1. axios.get으로 가져오는 정보에 타입 지정하기
const response = await axios.get<PokemonData>(url);
  1. 함수 params에 타입 지정하기
const filterDisplayedPokemonData = (
  allPokemonsData: PokemonNameAndUrl[],
  displayedPokemons: PokemonNameAndUrl[] = []
) => {
  ...
} 
  1. return 부분 map params에 타입 지정하기
{displayedPokemons.map(({url, name}: PokemonNameAndUrl) => ( ... ))}
  1. setState에 타입 지정하기
setState: React.Dispatch<React.SetStateAction<number>>;

그 외 React에서 어떻게 TypeScript를 사용하는지는
React-TypeScript-CheatSheet에 잘 나와있으니 참조!


컴포넌트 props에 타입 지정하는 컨벤션

interface ComponentProps {
  props1: string[],
  props2: React.Dispatch<React.SetStateAction<string>>
}

const Component = ({ props1, props2 }: ComponentProps) => {
  ...
}

이벤트 객체의 경우

const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
  ...
}

keyof typeof

const newSprites = {...sprites};

(Object.keys(newSprites) as (keyof typeof newSprites)[]).forEach((key => {
  ...
})
  • newSprites는 객체이다.
  • keyof는 타입의 키를 가져오는 것 이므로, 객체에 바로 사용 불가함.
  • 따라서 typeof 를 한 번 해주고나서 keyof를 해줘야 함.
type Point = {x: number, y:number};
type P = keyof Point; // "x" | "y"

타입 단언 (as)

  • TypeScript보다 어떤 값의 타입을 보다 명확하게 알고 있을 때 활용
  • 타입 선언(:type)과는 다름.
  • 즉, 타입 단언은 강제로 타입을 지정했으니 체크를 하지 않음.

[Tool] quickType


await

  • await은 Promise를 반환
  • 그 타입을 <> 안에 적어주면 됨 (string)
const getDescription = async (id: number): Promise<string> => {
  ...
  return descriptions;
}

useRef

  1. 변수로 사용하는 경우
  • 초기 값을 제네릭 타입과 같은 타입으로 넣어주기.
const varRef = useRef<number>(0);
  1. DOM을 조작하기 위해 사용하는 경우
  • 초기 값(HTMLElement)을 넣어주기
const ref = useRef<HTMLDivElement>(null);
const inputRef = useRef<HTMLInputElement>(null);

...

return(
  <div ref={ref}></div>
)
  • 위에서는 ref가 null이 될 수 있다.
  • 타입 가드(type guard)를 해줘야 함.
if (ref.current) {  // type guard
  ref.current.style.width = '100%'
}

useState

  • useState값이 객체거나 Null일때
const initialUserData = localStorage.getItem('userData') ? JSON.parse(localStorage.getItem('userData')) : null;
const [userData, setUserData] = useState<User | null>(initialUserData);

.d.ts 선언 파일 생성

uuid

  • 유니크한 아이디를 생성하는 모듈.
$ npm install uuid
  • app.tsx에서 임포트 시 선언 파일을 찾을 수 없다는 에러 발견됨.
import { v4 } from 'uuid';
  • 이와 같이 js로 작성된 모듈을 사용할 때, 타입이 지정되지 않은 경우
    • .d.ts 선언 파일을 생성해야 함.

uuid.d.ts 파일 생성

declare module 'uuid' {
  const v4: () => string;
  
  export { v4 };
}
  • 파일 명을 uuid.d.ts가 아닌 main.d.ts 등으로 변경하면 다시 에러가 남.
    • 자동으로 찾아주지 않기 때문에 Reference 태그를 사용해야함.

/// <refrence path=""/>

  • 파일의 최상단에 위와 같이 작성하면 해결됨.
  • 즉, 선언 파일(.d.ts)명이 모듈의 이름과 다른 경우에는 위와 같이 레퍼런스 태그를 사용해야 함.
/// <reference path="./main.d.ts" />

권장 방법

  • 위와 같이 직접 .d.ts 파일을 생성하는 것 보다는
  • 타입 선언 모듈을 설치해서 쓰는 것이 좋다!
$ npm install -D @types/{모듈명}

참고 - npm install uuid && npm install -D @types/uuid 둘 다 해야 함.


LocalStorage Wrapper 생성

  • localStorage 값을 가져올 때 Wrapper를 이용해보자.

/src/utils/storage.ts 파일 생성

const storage = {
  set: (key: string, value: any) => {
    localStorage.setItem(key, JSON.stringify(value));
  }, 
  
  get: <T>(key: string, defaultValue?: T): T => {
    const value = localStorage.getItem(key);
    return (value ? JSON.parse(value) : defaultValue) as T;
  },
  
  remove: (key: string) => {
    localStorage.removeItem(key)
  }
}
profile
기억은 한계가 있지만, 기록은 한계가 없다.

0개의 댓글