RN의 JS 코드를 TS로 변환하기

Sheryl Yun·2023년 4월 29일
1

React Native를 익히고 싶어서 노마드코더 강의를 듣는데 초반부터 크나큰 잘못(?)을 했다. 강의 코드에 맞춰 JS 코드로 시작했더니 개발 중에 에러가 거의.. 뜨지 않았다. 어제 다른 프로젝트에서 prettier와 eslint 파일 설정을 하면서 vscode 설정을 바꿔서인지 모르겠는데 import가 안 된 것도 못 잡아줄 정도.. (사실 JS를 쓴 게 너무 오래 되어서 JS가 잡는 에러의 범위가 어디까지였는지 기억이 나지 않는다)

에러 없이 너무 멀쩡한 에디터 창과, 실행만 했다 하면 쉴새없이 에러가 터지는 모바일 화면을 번갈아 쳐다보다 결국 타입스크립트 코드로 변환하기로 했다. (조용한 에디터 창이 이렇게 얄미울 줄 몰랐음. 많은 문제를 안고 있지만 아무 것도 모른다는 듯 해맑은 표정으로 나를 바라보지만 막상 실행하면 사고 부르스)

날씨 앱을 만들기 위해 짜고 있던 App.js 코드는 대략 이러했다. (StyleSheet은 분리하기 전)

import { StyleSheet, Text, View, StatusBar } from 'react-native';
import PaginationDot from 'react-native-animated-pagination-dot';
import { Date, Icon, Const } from './utils';
import { getWeather } from './api/getWeather';
import { COLOR } from './styles/color';

export default function App() {
  const weatherData = getWeather();

  const { weather, main } = weatherData;

  return (
    <View style={{ flex: 1, backgroundColor: COLOR.primary }}>
      <View
        style={{
          flexDirection: 'row',
          justifyContent: 'space-between',
          padding: 24,
        }}
      >
        {Icon.BARS_ICON}
        <Text style={{ fontSize: 18, fontWeight: 700 }}>{Const.CITY_NAME}</Text>
        {Icon.SEARCH_ICON}
      </View>
      <View style={{ flex: 1.2, margin: 24, borderBottomWidth: 3 }}>
        <Text style={{ fontSize: 20, fontWeight: 700 }}>{Date.DAY}</Text>
        <Text style={{ fontSize: 16 }}>
          {Date.MONTH}&nbsp;
          {Date.DATE}</Text>
      </View>
      <View style={{ flex: 3.5, margin: 24, borderBottomWidth: 3 }}>
        <Text style={{ fontSize: 100, fontWeight: 700 }}>{main.temp}°</Text>
        <Text style={{ fontSize: 16 }}>{weather[0].main}</Text>
      </View>
      <View style={{ flex: 2, margin: 24 }}>
        <View
          style={{
            flexDirection: 'row',
            justifyContent: 'space-between',
          }}
        >
          <Text style={{ fontWeight: 700 }}>최고 {main.temp_max}°</Text>
          <Text style={{ fontWeight: 700 }}>
            {weatherData.rain
              ? `강수량 ${detail.rain['1h']}`
              : weatherData.snow
              ? `강우량 ${detail.rain['1h']}`
              : weatherData.clouds
              ? `흐림 ${detail.clouds.all}%`
              : '맑음'}
          </Text>
        </View>
        <View
          style={{
            flexDirection: 'row',
            justifyContent: 'space-between',
          }}
        >
          <Text>최저 {main.temp_min}°</Text>
          <Text>바람속도 {Math.floor(weatherData.wind.speed)} km/h</Text>
        </View>
      </View>
      <View style={{ padding: 24, alignItems: 'center' }}>
        <PaginationDot activeDotColor={'black'} curPage={page} maxPage={4} />
      </View>
      <StatusBar barStyle='dark-content' backgroundColor={COLOR.primary} />
    </View>
  );
}

이 상태에서 에러가 나는 곳이 어딘지를 모른 채 모바일 화면에서는 빨간색 에러 창이 떴다. 자바스크립트를 타입스크립트로 바꾸는 방법을 찾아보았다.

검색한 결과의 TLDR을 보니 다음과 같이 간단했다.

타입스크립트 환경 설정 및 ts 파일로 변환
any 타입 선언
any 타입을 더 적절한 타입으로 변경

즉, TS 환경 설정을 하고 .js 확장자를 .ts로 바꿔주고 함수 반환값, 매개변수 등에 구체적인 타입을 선언해주면 되나보다.

우선 .js 파일들을 .ts 또는 (JSX가 포함된 경우) .tsx로 바꿔주었다.

크.. 첫 번째 파일을 .ts로 바꾸자마자 이렇게 에러가 뜬다. axios 임포트 안 되어 있었지만 나는 몰랐고 자바스크립트도 몰랐는데(?) 너무 좋다. (여담: axios 고치고 나니 baseUrl도 base'URL'이었다. 자바스크립트는 암것도 몰라..)

그 다음 react-native 패키지에서 가져오는 Text, View 같은 컴포넌트들을 인식을 못 해서 RN을 타입스크립트에 인식시키는 패키지들을 설치하고 tsconfig.json을 설정했다.

npm install typescript @types/react @types/react-native --save-dev

{
  "compilerOptions": {
    "allowJs": true,
    "allowSyntheticDefaultImports": true,
    "esModuleInterop": true,
    "isolatedModules": true,
    "jsx": "react-jsx",
    "lib": ["es6", "es2020"],
    "moduleResolution": "node",
    "noEmit": true,
    "strict": true,
    "target": "esnext",
    "skipLibCheck": true
  },
  "exclude": [
    "node_modules",
    "babel.config.js"
  ]
}

RN을 처음부터 타입스크립트로 설정하는 명령어도 있었다. (시작할 때 template을 typescript로 지정)

npx react-native init [프로젝트명] --template react-native-template-typescript

이 외에도 typescript와 @types를 붙인 패키지들을 추가로 설치했다.

"typescript": "^4.9.4"
"@types/react-native-vector-icons": "^6.4.13",
"@types/node": "^18.16.3",

export * as ~ 구문을 사용한 utils/index.ts에서 'Export namespace should be first transformed by @babel/plugin-proposal-export-namespace-from' 라는 에러가 계속 떴는데 babel.config.js의 plugins에 '@babel/plugin-proposal-export-namespace-from'를 추가해주니 해결되었다.

module.exports = function (api) {
  api.cache(true);
  return {
    presets: ['babel-preset-expo'],
    plugins: [
      [
        'module:react-native-dotenv',
        {
          moduleName: 'react-native-dotenv',
        },
      ],
      '@babel/plugin-proposal-export-namespace-from', // 추가
    ],
  };
};

추가로 절대경로 설정을 위해 babel.config.js의 plugins에 다음을 더 추가했다.

 plugins: [
      [
        "module-resolver",
        {
          "root": [
            "."
          ],
          "extensions": [
            ".ts",
            ".tsx"
          ]
        }
      ],
   	...
   ]

tsconfig.json에는 compilerOptions에 이 한 줄 추가

    "baseUrl": ".",

이후 에디터를 껐다 켜니 절대 경로가 잘 적용되었다.


나중에 openweathermap API의 날씨 아이콘이 잘 적용되는데도 브라우저에 계속 404 에러가 떠서 Stackoverflow에 질문을 올렸다. 여기 내용을 참고는 많이 했어도 질문을 올리는 것은 처음이다.

질문 올린 stackoverflow 링크

언제 가입했는지 아이디가 기념

profile
데이터 분석가 준비 중입니다 (티스토리에 기록: https://cherylog.tistory.com/)

0개의 댓글