JS를 TSX 로 포팅하기

jeongjwon·2023년 6월 1일
0

SEB FE

목록 보기
54/56

TSX 로 포팅하기

package 설치

저장소를 git clone 한 후 , 필요한 package 를 추가적으로 설치한다.

  • npm install -g typescript : typescript 패키지
  • @types/react @types/react-dom : 타입 정의 파일
  • @typescript-eslint/eslint-plugin @typescript-eslint/parser eslint : typescript-eslint 적용하기 위한 typescript, eslint, typescript-eslint 관련 패키지
  • eslint-config-prettier eslint-plugin-prettier eslint-plugin-react eslint-plugin-react-hooks prettier : typescript-eslint + prettier 적용 관련 패키지


tsconfing.json

vsCode 에서 tsconfig.json을 참고해서 타입스크립트 문법을 검사한다. 뿐만 아니라 웹팩에서 설정할 ts-loader가 이 파일을 참고해서 트랜스파일 작업을 하기 때문에 tsconfig.json 파일은 먼저 생성해야 한다.

{
    "compilerOptions": {
        "jsx": "react-jsx",
        "lib": ["es6", "dom"],
        "rootDir": "src",
        "module": "CommonJS",
        "esModuleInterop": true,
        "target": "es5",
        "sourceMap": true,
        "moduleResolution": "node",
        "noImplicitReturns": true,
        "noImplicitThis": true,
        "noImplicitAny": true,
        "strictNullChecks": true,
        "allowJs": true
    },
    "include": ["./src"],
    "exclude": ["node_modules", "build"]
}
  • compilerOptions
    // 기본 옵션
    • jsx: .tsx 확장자의 컴파일 결과 JSX 코드를 컴파일할 방법 결정

    • lib: 컴파일에 필요한 JavaScript 내장 라이브러리 지정

    • rootDir: 루트 디렉토리 기준 변경하는 것으로 js 아웃풋 경로에 영향

    • module: 프로그램에서 사용할 모듈 시스템 (target 프로퍼티가 es5로 지정되었을 때 CommonJS 로 지정)

    • esModuleInterop: 모든 가져오기에 대한 네임스페이스 객체 생성을 통해 CommonJS와 ES 모듈 간의 상호 운용성 제공

      • true 일 경우 ```import React from "react";
      • false 일 경우 ```import * from React from "react";
    • target: 컴파일할 JavaScript 버전 지정

    • sourceMap: 컴파일된 파일 디렉터리에 .js.map 파일 생성 설정

    • moduleResolution : module 프로퍼티에 따라 결정하는 것으로 모듈 분석 방법을 설정

      • module: commonJs -> moduleResolution: node
      • module: amd(web) -> moudleResolution: classic
    • allowJs: JavaScript 파일 컴파일 허용

      // 엄격한 유형 검사 옵션

    • noImplicitReturns: 함수에서 return 없으면 에러

    • noImplicitThis: 명시적이지 않은 any 유형으로 this 표현식 사용시 에러

    • noImplicitAny: 명시적이지 않은 any 유형으로 표현식 및 선언 사용시 에러

    • strictNullChecks: 엄격한 null 검사 사용

  • include : 프로젝트에서 컴파일할 파일들을 지정하는 속성
  • exclude : 프로젝트에서 컴파일 대상에서 제외할 파일들을 지정하는 속성


.eslintrc.js

ESLint: JavaScript 의 문법을 확인해주는 도구

module.exports = {
    root: true,
    env: {
        browser: true,
        node: true,
    },
    extends: [
        "plugin:@typescript-eslint/eslint-recommended",
        "plugin:@typescript-eslint/recommended",
        "plugin:prettier/recommended",
    ],
    rules: {
        "prettier/prettier": [
            "error",
            {
                doubleQuote: true,
                semi: true,
                useTabs: false,
                tabWidth: 4,
                printWidth: 80,
                bracketSpacing: true,
                arrowParens: "avoid",
            },
        ],
    },
    parserOptions: {
        parser: "@typescript-eslint/parser",
    },
};
  • env: 사용 환경
  • extends: 확장 기능 사용
  • rules: 세부 설정 규칙 추가
  • parserOptions: 버전과 모듈 사용 여부

vsCode 익스텐션에서 eslintprettier 를 설치해준다.
이를 통해 오류를 검사할 수 있다.





컴포넌트 포팅하기

설정을 다 마친 후, .js.tsx 파일명을 변경해준다.
그러면 수많은 오류들이 터미널과 파일에 빨간줄을 통해 출력이 된다.

포팅하는 법은 타입 지정, props 들을 type이나 interface 로 설정해준다.

App.tsx

  1. 최상위 컴포넌트 App 에서 사용되는 상태는 todo 가 배열 형식으로된 todos 이므로 가장 기본적인 todo를 type TodoProps으로 생성해준다.
  2. TodoProps 의 프로퍼티로는 빨간줄로 표시된 오류에서 id, text, isComplete 를 찾아낼 수 있다. 각각의 타입을 number, string, boolean 으로 지정해준다.
type TodoProps = {
  id: number;
  text: string;
  isComplete: boolean;
}
  1. 생성된 타입을 이용해서 객체를 생성해준다. 이미 useStatetodos 로 생성이 되어 있는데 여기서 타입을 추가해주는데 todos는 todo를 배열형식으로 만든 것이기 때문에 타입을 형식에 맞춰 작성한다.
const [todos, setTodos] = useState<TodoProps[]>([]);
  1. 자식 컴포넌트로 전달할 함수 메서드 addTodo, removeTodo, completeTodo 에는 각각 todo, id, id 가 매개변수로 필요한 것을 알고 있고 이것을 타입만 지정해주면 된다.
const addTodo = (todo: TodoProps) => {...}

const removeTodo = (id: number) => {...}

const completeTodo = (id: number) => {...}


Todo.tsx

  1. App.tsx 에서 전달받은 props는 todos, completeTodo, removeTodo 임을 알 수 있고 이 프로퍼티를 interface TodoListProps로 설정해준다.
  2. interface TodoListProps 안의 프로퍼티들은 각각의 타입을 지정해준다. 이때 App 에서 만들어준 TodoProps 를 사용한다.
  • todostodo를 가르키는 TodoProps를 배열화 한 것이다.
  • completeTodoremoveTodo 는 매개변수를 id 로 받는 void형 함수이다.
interface TodoListProps{
  todos: TodoProps[];
  completeTodo(id:number):void;
  removeTodo(id:number):void;
}
  1. 컴포넌트의 props를 생성한 TodoListProps interface 로 타입을 지정해준다.
function Todo({props}:TodoListProps){ ... }



TodoForm.tsx

  1. props로 받은 onSumbit 이벤트 함수를 interface TodoForm으로 지정해준다.

    이때, 전달인자는 isComplete 프로퍼티가 빠진 TodoProps 타입을 알 수 있으며 void 형인 함수이다.

interface TodoFormProps {
    onSubmit(todo: TodoProps):void;
}
  1. useState로 지정한 상태들도 type을 지정해준다.
const [input, setInput] = useState<string>("");
const [number, setNumber] = useState<number>(1);

문제 해결하기

  1. TodoProps
  • TodoForm 에서 알 수 있듯이 onSubmit 함수의 전달인자는 todo인데, 그 중 isComplete 프로퍼티는 생략이 된 것을 알 수 있다. 따라서 todo를 나타내는 TodoProps type에서 isComplete 프로퍼티는 생략가능한 프로퍼티이므로 ? 키워드를 추가한다.
  • TodoPropsTodoFormTodo 컴포넌트에 사용되어 각각의 파일에서 import 를 해준다. import를 해주기 위해서는 해당 App 폴더에서 export를 해주어야만 다른 파일에서 사용가능하다.

  1. 이벤트 핸들러 함수

    이벤트 핸들러 함수에서는 e.target.value를 전달하기 위해 매개변수 e가 필요하다. 타입을 잘 모르겠어서 any로 설정해주었는데 기본값이 any형식으로 포함이 되기 때문에 굳이 설정해줄 필요가 없고 더 명확하게 타입을 명시해야 한다.
    리액트에서는 이벤트 관련 타입을 지정해주기 때문에, 어떤 이벤트 타입인지, 그 이벤트가 발생하는 HTML 요소 타입이 무엇인지 알면 제네릭을 이용해 지정해줄 수 있다.
  • onSumbit 은 React.FormEvent 관련 이벤트 타입으로 <HTMLFormElement> 요소 타입이다.

  • onChange 는 React.ChangeEvnet 관련 이벤트 타입으로 <HTMLInputElement> 요소 타입이다.


  1. useRef
useRef 는 null로 초기화가 되어있고 타입지정을 무엇으로 해주어야 할 지 도무지 생각해도 잘 생각이 안났다.

그러다 useRef 가 사용되는 곳에서 마우스를 대 보니 <HTMLInputElement> 요소 타입인 것을 알아냈고, 위 이벤트 핸들러처럼 사용하였다.

하지만 타입을 지정해주어도 useEffect 내에서 inputRef.current 에 빨간줄 오류가 떴고, 이 값은 null 이 될 수도 있다는 뜻이었다.

null을 해결해주기 위해서 해당 분기를 해주었는데, 이보다 더 나은 방법은 없을까,,,?

? 키워드를 사용해서 선택적으로 null이 아닌 값만 자동적으로 받을 수 있게 수정하였다.


  1. index.tsx

index.tsx 에서도 타입을 지정해주어야 했는데, document.getElementById()HTMLElement | null 형식이라고 도움을 주었다.

따라서 as 타입 단언을 이용해 HTMLElement 타입을 지정해주었다.





마치며

이론은 참 쉽게 느껴지고 포팅을 마치 후에는 그닥 어렵지 않은데 왜 시작이 항상 어려운지 모르겠다.
내 문제는 항상 어렵다고 회피하기 일수였지만, 이번 TIL 을 통해 조금이나마 포팅하는 방법을 외우는 방법이 아닌 이해하는 형식으로 배우게 되었다.

어렵게 생각하지말고 낯설다 라고 되뇌이며 노력해보자!

reference

https://inpa.tistory.com/entry/TS-%F0%9F%93%98-%ED%83%80%EC%9E%85%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-tsconfigjson-%EC%84%A4%EC%A0%95%ED%95%98%EA%B8%B0-%EC%B4%9D%EC%A0%95%EB%A6%AC#include

http://yoonbumtae.com/?p=4440

0개의 댓글