Skip to main content

TypeScript 사용하기

TypeScript는 타입 정의를 추가해 JavaScript를 확장한 언어이다. 새로운 React Native 프로젝트는 기본적으로 TypeScript를 대상으로 하지만, JavaScript와 Flow도 지원한다.

TypeScript 시작하기

React Native CLI로 생성한 새 프로젝트나 Ignite와 같은 인기 있는 템플릿은 기본적으로 TypeScript를 사용한다.

TypeScript는 Expo와도 함께 사용할 수 있다. Expo는 TypeScript 템플릿을 제공하며, 프로젝트에 .ts 또는 .tsx 파일이 추가되면 자동으로 TypeScript를 설치하고 설정하도록 안내한다.

shell
npx create-expo-app --template

기존 프로젝트에 TypeScript 추가하기

  1. 프로젝트에 TypeScript, 타입 정의, ESLint 플러그인을 추가한다.
shell
npm install -D @tsconfig/react-native @types/jest @types/react @types/react-test-renderer typescript
note

이 명령어는 모든 의존성의 최신 버전을 추가한다. 프로젝트에서 사용 중인 기존 패키지와 버전을 맞추기 위해 버전을 변경해야 할 수 있다. React Native Upgrade Helper와 같은 도구를 사용해 React Native에서 제공하는 버전을 확인할 수 있다.

  1. TypeScript 설정 파일을 추가한다. 프로젝트 루트에 tsconfig.json 파일을 생성한다:
json
{
"extends": "@tsconfig/react-native/tsconfig.json"
}
  1. JavaScript 파일을 *.tsx로 변경한다.

./index.js 엔트리포인트 파일은 그대로 두는 것이 좋다. 그렇지 않으면 프로덕션 빌드를 번들링할 때 문제가 발생할 수 있다.

  1. tsc를 실행해 새로운 TypeScript 파일의 타입을 검사한다.
shell
npx tsc

타입스크립트 대신 자바스크립트 사용하기

React Native는 새로운 애플리케이션을 기본적으로 타입스크립트로 설정한다. 하지만 여전히 자바스크립트를 사용할 수 있다. .jsx 확장자를 가진 파일은 타입스크립트가 아닌 자바스크립트로 처리되며, 타입 검사가 이루어지지 않는다. 자바스크립트 모듈은 타입스크립트 모듈에서 가져올 수 있으며, 그 반대도 가능하다.

TypeScript와 React Native의 동작 방식

기본적으로 TypeScript 소스 코드는 번들링 과정에서 Babel에 의해 변환된다. TypeScript 컴파일러는 타입 검사만을 위해 사용하는 것을 권장한다. 이는 새로 생성된 애플리케이션에서 tsc의 기본 동작이다. 기존의 TypeScript 코드를 React Native로 포팅하는 경우, TypeScript 대신 Babel을 사용할 때 주의해야 할 몇 가지 사항이 있다.

React Native + TypeScript 예제 살펴보기

React 컴포넌트의 PropsState에 인터페이스를 제공하려면 React.Component<Props, State>를 사용한다. 이렇게 하면 JSX에서 해당 컴포넌트를 작업할 때 타입 검사와 에디터 자동 완성 기능을 활용할 수 있다.

components/Hello.tsx
import React from 'react';
import {Button, StyleSheet, Text, View} from 'react-native';

export type Props = {
name: string;
baseEnthusiasmLevel?: number;
};

const Hello: React.FC<Props> = ({
name,
baseEnthusiasmLevel = 0,
}) => {
const [enthusiasmLevel, setEnthusiasmLevel] = React.useState(
baseEnthusiasmLevel,
);

const onIncrement = () =>
setEnthusiasmLevel(enthusiasmLevel + 1);
const onDecrement = () =>
setEnthusiasmLevel(
enthusiasmLevel > 0 ? enthusiasmLevel - 1 : 0,
);

const getExclamationMarks = (numChars: number) =>
numChars > 0 ? Array(numChars + 1).join('!') : '';

return (
<View style={styles.container}>
<Text style={styles.greeting}>
Hello {name}
{getExclamationMarks(enthusiasmLevel)}
</Text>
<View>
<Button
title="Increase enthusiasm"
accessibilityLabel="increment"
onPress={onIncrement}
color="blue"
/>
<Button
title="Decrease enthusiasm"
accessibilityLabel="decrement"
onPress={onDecrement}
color="red"
/>
</View>
</View>
);
};

const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
greeting: {
fontSize: 20,
fontWeight: 'bold',
margin: 16,
},
});

export default Hello;

더 자세한 문법은 TypeScript playground에서 확인할 수 있다.

유용한 정보를 찾을 수 있는 곳

커스텀 경로 별칭을 TypeScript와 함께 사용하기

TypeScript에서 커스텀 경로 별칭을 사용하려면 Babel과 TypeScript 모두에서 경로 별칭이 작동하도록 설정해야 한다. 방법은 다음과 같다:

  1. tsconfig.json을 수정해 커스텀 경로 매핑을 설정한다. src 루트의 모든 파일을 경로 참조 없이 사용할 수 있게 하고, tests/File.tsx를 통해 테스트 파일에 접근할 수 있도록 한다:
diff
{
- "extends": "@tsconfig/react-native/tsconfig.json"
+ "extends": "@tsconfig/react-native/tsconfig.json",
+ "compilerOptions": {
+ "baseUrl": ".",
+ "paths": {
+ "*": ["src/*"],
+ "tests": ["tests/*"],
+ "@components/*": ["src/components/*"],
+ },
+ }
}
  1. 프로젝트에 개발 패키지로 babel-plugin-module-resolver을 추가한다:
shell
npm install --save-dev babel-plugin-module-resolver
  1. 마지막으로 babel.config.js를 설정한다 (babel.config.js의 문법은 tsconfig.json과 다르다는 점에 유의한다):
diff
{
presets: ['module:metro-react-native-babel-preset'],
+ plugins: [
+ [
+ 'module-resolver',
+ {
+ root: ['./src'],
+ extensions: ['.ios.js', '.android.js', '.js', '.ts', '.tsx', '.json'],
+ alias: {
+ tests: ['./tests/'],
+ "@components": "./src/components",
+ }
+ }
+ ]
+ ]
}