Skip to main content
Version: Next

타입스크립트 사용하기

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

TypeScript 시작하기

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

Expo에서도 TypeScript를 활용할 수 있다. 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

TypeScript 대신 JavaScript 사용하기

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

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 플레이그라운드를 확인해 보자.

유용한 조언을 찾을 수 있는 곳

타입스크립트에서 커스텀 경로 별칭 사용하기

타입스크립트에서 커스텀 경로 별칭을 사용하려면 Babel과 타입스크립트 양쪽에서 설정해야 한다. 방법은 다음과 같다:

  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",
+ }
+ }
+ ]
+ ]
}