[TIL] 230727

이세령·2023년 7월 27일
0

TIL

목록 보기
68/118

TypeScript Generics

정적 타입 언어에서는 특정 타입을 위해 만들어진 함수/클래스를 범용적으로 재사용하기 위해 제네릭이라는 기법을 사용한다.
ex) Stack 자료구조

class Stack<T> {
  private data: T[] = [];

  constructor() {}

  push(item: T): void {
    this.data.push(item);
  }

  pop(): T {
    return this.data.pop();
  }
}

const numberStack = new Stack<number>();
const stringStack = new Stack<string>();

이런식으로 타입을 지정할 수 있다.

React JS -> Ts 리팩토링

  • ts react로 프로젝트 생성
    # yarn을 사용하는 경우
    yarn create react-app my-app --template typescript
    
    # npx를 사용하는 경우
    npx create-react-app my-app --template typescript
  • 기존 프로젝트에 패키지 설치
    yarn add typescript @types/node @types/react @types/react-dom @types/jest
  • tsconfig 추가
        npx tsc --init
        yarn tsc --init
  • tsconfig 기본설정
        {
          "compilerOptions": {
            "allowJs": true,
            "target": "ES5",
            "outDir": "./dist",
            "moduleResolution": "Node",
            "lib": ["ES2015", "DOM", "DOM.Iterable"]
          },
          "include": ["./src/**/*"],
          "exclude": ["node_modules", "dist"]
        }

변환해야할 시 해야하는 것

  • js, jsx를 tsx 파일로 변경
  • 기존 설치된 패키지의 충돌을 확인하고 TS를 지원하는 패키지로 재 설치하자
  • Any 타입의 사용을 최대한 지양하고, 타입을 지정할 수 있는 모든 곳에 타입을 지정하자
  • As를 최대한 사용하지 않도록 타입을 정확히 명시하자

Error: '--jsx' is not set

  • VScode에서 TypeScript의 버전이 제대로 설정돼있지 않아서 뜨는 오류
    Ctrl + Shift + P 로 커맨드 창 열기

TypeScript: Select a TypeScript Version 검색하여 버전 선택해주기
-> 해결되지 않아서 더 검색

  • compilerOptions에서 jsx 의 설정이 제대로 되어있지 않아 생긴 문제
{
  "compilerOptions": {
    "target": "es6",
    "module": "commonjs",
    "esModuleInterop": true,
    "noImplicitAny": true,
    "strictNullChecks": false,
    "jsx": "react",
    "sourceMap": true,
    "typeRoots": [
      "src/@types/types"
    ],
  }
}

라고 되어있어서
"jsx": "react"만 지정해주니 해당 문제는 해결되었다.
-> 다른 에러가 발생해서 stack overflow를 확인해보니
react-jsx 이렇게 지정해주어야 한다.

  • typescript버전 4.1 이상
  • react그리고 react-dom버전 17 이상
  • tsconfig.json또는 jsx의 compilerOption이 있어야 합니다.react-jsxreact-jsxdev

Error: Cannot find name 'localStorage'

tsconfig.json에서 "lib": [ "ES2016", "DOM", "DOM.Iterable" ] 으로 변경
DOM이 없어서 오류가 발생했던 것이다.

Error: 기본 세팅들 오류

TypeScript로 생성된 프로젝트에서 코드를 가져왔다.
reportWebVitals.ts

import { ReportHandler } from 'web-vitals';

const reportWebVitals = (onPerfEntry?: ReportHandler) => {
  if (onPerfEntry && onPerfEntry instanceof Function) {
    import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
      getCLS(onPerfEntry);
      getFID(onPerfEntry);
      getFCP(onPerfEntry);
      getLCP(onPerfEntry);
      getTTFB(onPerfEntry);
    });
  }
};

export default reportWebVitals;

index.tsx
root 부분만 변경

const root = ReactDOM.createRoot(
  document.getElementById('root') as HTMLElement
);

내 코드 리펙토링

이제 본격적으로 컴포넌트들에서 타입 지정을 해보자

문서를 참고
https://react-typescript-cheatsheet.netlify.app/docs/basic/getting-started/basic_type_example

App.tsx

event

title과 content를 입력하는 코드들에서 event에 type 지정을 해주어야한다.
이벤트 찾기 -> 제네릭으로 전달

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

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

Error: ~ does not exist on type 'never'

특정 데이터를 불러오는데 데이터의 명확한 타입을 모를 경우에 나타난다.
useState([])이런 형태에 담아 사용할 텐데 다음과 같이 수정하면 된다.

const [working, setworking] = useState<any[]>([]);

working과 관련된 에러가 사라진다.

TextArea Element

textarea를 다루는 컴포넌트에서 InputElement 제네릭으로 넘겨주었는데, 에러가 발생하여 찾아보니 TextArea가 따로 있었다.

const newContentHandler = (event: React.ChangeEvent<HTMLTextAreaElement>) => {
    setnewContent(event.target.value);
  };

HTML DOM API는 다음을 참고하면 된다.

https://developer.mozilla.org/en-US/docs/Web/API/HTML_DOM_API#html_dom_api_interfaces

props type

코드를 수정하고 실행하기 위해 props:any로 전부 수정해주었다. -> 더 명확하게 바꾸기!

type

type을 모아둬서 파일을 정리할 수 있다.

export type Restaurant = {
	name: string;
    category: string;
}

interface extends

이렇게 interface도 extends가 가능하다.

interface 새로운것 extends 미리정의한것 {
  추가...
}

수정 리팩토링

수정을 위한 input과 textarea가 다른 컴포넌트에 있기 때문에 ref로 해당 DOM을 지정해준다.

{updateState && (
        <div className="update-box" ref={updateBoxRef}>
          <UpdateContent item={props.item}></UpdateContent>
        </div>
      )}

TypeScript에서는 어떤 타입인지 지정해주어야 하기 때문에 그냥 querySelector를 사용하면 안된다.

// 수정 title, content
    const findUpdateBoxTitle = (
      updateBoxRef.current?.querySelector(".update-title") as HTMLInputElement
    )?.value;

    const findUpdateBoxContent = (
      updateBoxRef.current?.querySelector(
        ".update-content"
      ) as HTMLTextAreaElement
    )?.value;

typescript에서 type만 지정해주면 될줄 알았는데, DOM요소의 type을 알아야한다. TypeScript를 복습하면서 문서를 읽는 것에 익숙해지고 DOM요소를 더 알아봐야겠다.

profile
https://github.com/Hediar?tab=repositories

0개의 댓글