[ 앱 개발자 도전기 : 크로스플랫폼_ReactNative ] React Native 입문을 위한 필수 TS 개념 정리 01.

0

App_Dev : RN

목록 보기
11/17
post-thumbnail

[ 앱 개발자 도전기 : 크로스플랫폼_ReactNative ] React Native 입문을 위한 필수 TS 개념 정리 01.

▽ React Native 입문을 위한 필수 TS 개념 정리 01.

목  차

1. JS vs TS의 차이.

2. TypeScript를 쓰는 이유: 안정성과 예측 가능성

3. React Native에서 TypeScript 적용 장점.

4. TypeScript 기본 타입 정리.

5. 유니언, 튜플, 리터럴 타입 활용

6. 타입 추론 vs 명시적 선언

1. JS vs TS의 차이


📌1-1. 개요

📘 공식 문서 개념 설명

  • JavaScript (JS)

    • ECMAScript 사양을 따르는 웹 표준 언어로, 동적 타이핑 기반이며 런타임에서 변수의 타입이 결정됩니다.
    • 빠르게 작성할 수 있지만 대규모 프로젝트에서는 버그 유입이 잦고 유지보수가 어렵습니다.
      https://developer.mozilla.org/en-US/docs/Web/JavaScript
  • TypeScript (TS)

    • Microsoft가 만든 JS의 Superset(상위 집합)으로, 정적 타입 시스템을 도입해 컴파일 타임에 오류를 탐지할 수 있으며 코드 가독성과 예측 가능성이 높습니다.
    • TS 코드는 컴파일을 통해 JS로 변환되어 실행됩니다.
      https://www.typescriptlang.org/docs/handbook/intro.html

💡 실무 활용 방안.

  • 작은 프로젝트에서는 JS로 빠르게 구현 가능하지만,

  • 팀 개발/대규모 앱에서는 TypeScript 도입을 통해 코드 안정성과 유지보수성을 확보.

  • 특히 React Native처럼 UI와 Native API가 밀접한 프레임워크에서는 예측 가능한 코드가 필수.

💻 예제 코드

// JavaScript
function multiply(a, b) {
  return a * b; // 문자열 입력 시 NaN 반환
}

// TypeScript
function multiply(a: number, b: number): number {
  return a * b; // 타입 불일치 시 컴파일 에러 발생
}

📌1-2. 문법과 타입 시스템 비교

📘 공식 문서 개념 설명

  • 정적 타입 vs 동적 타입

    • JS는 변수의 타입이 런타임에 결정되며, 실수로 다른 타입이 들어가도 에러가 발생하지 않습니다.
    • 반면 TS는 컴파일 타임에 타입 체크를 하므로 에러를 사전에 방지할 수 있습니다.
  • 컴파일 타임 체크 vs 런타임 에러

    • TS는 코드를 실행하기 전에 타입 오류를 잡습니다.
    • JS는 오류가 발생하더라도 런타임까지 알아채기 어렵습니다.
  • 인터페이스, 제네릭, 열거형 등 TS 고급 문법.

    • TS는 인터페이스, 타입 별칭, 제네릭, 열거형(enum) 등 JS에 없는 기능을 제공하여 코드의 구조를 명확하게 만듭니다.

💡 실무 활용 방안.

  • 타입 기반 개발 → IDE 자동완성, 리팩토링, 테스트에 큰 이점.

  • 인터페이스 기반의 컴포넌트 설계가 표준화된 협업에 유리.

💻 예제 코드

// Type alias
type UserId = number | string;

// Interface
interface User {
  id: UserId;
  name: string;
}

// Function with type safety
function printUser(user: User): void {
  console.log(`${user.id}: ${user.name}`);
}

📌1-3. 개발 환경과 도구 지원

  • VSCode 기반 자동완성 & IntelliSense 강화

    • 타입을 바탕으로 자동완성, 문서 추론, 오류 탐지 기능이 강화됨.
  • TSLint / ESLint + TypeScript 지원

    • 코드 스타일 검사와 함께 타입 검사까지 가능.
  • React Native와의 자연스러운 통합

    • Expo CLI 및 React Native CLI 모두에서 TypeScript 템플릿을 공식 지원.
    • npx create-expo-app MyApp --template 사용 시 TS 자동 설정.

💡 실무 활용 방안.

  • Expo + TypeScript: npx create-expo-app --template

  • 개발 초기 세팅 시부터 TS 도입 권장

  • ESLint, Prettier와 함께 사용하면 코드 일관성과 품질 확보

💻 예제: Expo 프로젝트 TS 템플릿으로 생성

npx create-expo-app MyApp --template
// App.tsx
export default function App() {
  return <Text>Hello TypeScript</Text>;
}

2. TypeScript를 쓰는 이유: 안정성과 예측 가능성


📌2-1. 안정성

📘 공식 문서 개념 설명

  • Type Checking:
    • 타입을 기반으로 컴파일 타임에 오류를 사전에 탐지.
  • Strict Type Checking Options:
    • 엄격한 타입 검사로 예기치 못한 에러 감소.
  • 팀 내 코드 일관성 유지(일관된 코드베이스)
    • 팀원 간 타입 규약을 통해 일관된 코드 작성 가능
  • React Native의 동적 특성과 궁합
    • 네이티브 브리징, 이벤트 핸들링 등 JS 기반 특성에서 발생할 수 있는 오류를 줄일 수 있습니다.

💡 실무 활용 방안.

  • API 통신, Native 모듈과의 브리징에서 타입을 통해 오류 방지.

  • 팀원 간 타입 명세를 기반으로 안전한 인터페이스 공유 가능.

💻 예제 코드

interface Product {
  id: number;
  name: string;
  price: number;
}

function printProduct(p: Product) {
  console.log(`${p.name}: $${p.price}`);
}

// 실수로 price를 string으로 넘기면 컴파일 에러 발생

📌2-2. 예측 가능성

  • 타입 기반 API 설계(API 명세화 효과)

    • 타입으로 API 구조를 문서처럼 표현 가능합니다.
  • 함수 입력/출력 명확성

    • 인자와 반환 타입을 명시하여 함수 사용이 예측 가능해집니다.
  • 리팩토링 시 코드 붕괴 방지(리팩토링에 강함)

    • 타입 시스템이 구조 변경 시 에러를 포착해줍니다.
  • Context, Reducer 등의 구조적 설계와 잘 맞음

    • 상태 관리 구조에 타입을 지정하여 버그 감소.

📌2-3. 생산성과 협업 향상

📘 공식 문서 개념 설명

  • Editor Integration: 타입 기반 자동완성과 오류 탐지 제공

  • Type as Documentation : 타입은 곧 문서

💡 실무 활용 방안

  • Onboarding 시 타입만 읽어도 구조 파악 가능
  • Figma → Component 설계 시 props 명세로 디자이너와 커뮤니케이션 강화

💻 예제 코드

interface ButtonProps {
  label: string;
  onPress: () => void;
  variant?: 'primary' | 'secondary';
}

const Button: React.FC<ButtonProps> = ({ label, onPress, variant = 'primary' }) => {
  // variant 값에 따라 스타일 분기 가능
};

3. React Native에서 TypeScript 적용 장점


📌3-1. 컴포넌트와 Props의 타입 정의

  • Props/State 명시적 타입 지정:

    • props의 타입을 명확히 하여 불필요한 런타임 에러 방지

    • Props에 타입을 부여하여 자동완성과 타입 보호를 동시에 확보.

  • 컴포넌트 재사용 시 타입 기준으로 명세화가 되어 있음.

  • 불필요한 런타임 에러 방지

    • props를 잘못 넘겨서 생기는 에러를 컴파일 단계에서 막을 수 있습니다.

💻 예제 코드.

interface AvatarProps {
  uri: string;
  size?: number;
}

const Avatar = ({ uri, size = 50 }: AvatarProps) => {
  return <Image source={{ uri }} style={{ width: size, height: size }} />;
};

📌3-2. 네비게이션과 라우팅의 타입 안정성

  • React Navigation 사용 시 route param 타입 정의 가능

  • 잘못된 param 전달 시 컴파일 에러 발생하여, 런타임 에러를 줄여줍니다.

  • useNavigation/useRoute에서 제네릭으로 안전한 사용 가능

  • StackParamList를 사용해 route params 타입 정의

💻 예제 코드

type RootStackParamList = {
  Home: undefined;
  Profile: { userId: string };
};

const ProfileScreen = () => {
  const route = useRoute<RouteProp<RootStackParamList, 'Profile'>>();
  console.log(route.params.userId);
};

📌3-3. API 통신의 안정성 향상

  • API 응답 데이터의 타입을 지정해 파싱 에러 방지

    • API 응답 데이터의 타입을 정의해두면, 응답 파싱 시 타입 오류를 방지할 수 있습니다.
  • Axios나 react-query와 함께 사용하여 응답 데이터에 대한 타입 안전성 확보

💻 예제 코드

interface UserResponse {
  id: number;
  name: string;
}

const fetchUser = async (): Promise<UserResponse> => {
  const { data } = await axios.get('/user');
  return data;
};

📌3-4. 스타일과 외부 라이브러리 통합

  • 스타일 객체의 타입 안정성:

    • StyleSheet 객체에도 타입을 지정해, 스타일 관련 실수를 줄일 수 있습니다.
  • @types를 통해 외부 라이브러리 안정성 확보

    • 외부 라이브러리도 타입 정의 파일(@types/...)을 통해 안전하게 사용할 수 있습니다.

💻 예제 코드

import styled from 'styled-components/native';

const StyledText = styled.Text<{ color: string }>`
  color: ${(props) => props.color};
`;

📌3-5. 디버깅 및 테스트 개선.

  • 타입 기반으로 코드 흐름이 명확하여 디버깅이 쉬움

  • 타입 정보 덕분에 유닛 테스트 작성 시 예상 입력값 명확

  • Jest나 Detox 테스트에서 함수의 예상 입력값을 명확히 알 수 있어 테스트 작성이 용이.

💻 예제 코드

// 테스트 대상 함수
function sum(a: number, b: number): number {
  return a + b;
}

// Jest 테스트
it('adds two numbers', () => {
  expect(sum(1, 2)).toBe(3);
});

4. TypeScript 기본 타입 정리


📌4-1. 원시 타입 (Primitive Types)

  • string, number, boolean 등 JS와 동일합니다.
  • Basic Types: JavaScript의 원시 타입을 기반으로 하며, 타입 명시 가능
let name: string = 'TypeScript';
let age: number = 10;
let isActive: boolean = true;
  • 함수 인자나 반환 타입도 지정할 수 있습니다.
function greet(name: string): string {
  return `Hello, ${name}`;
}

📌4-2. 특수 타입

  • any: 어떤 타입도 허용하지만, 타입 안정성을 포기합니다.
let value: any = 10;
value = 'hello'; // 에러 없음
  • unknown: any와 비슷하지만, 사용 전에 타입 체크가 필요합니다.
let value: unknown = 10;
// value.toFixed(2); // 에러! number인지 확인 필요
  • void: 반환값이 없는 함수에 사용합니다.
function log(message: string): void {
  console.log(message);
}

  • never: 결코 값이 반환되지 않는 함수에 사용합니다. (예: 무한루프, 예외 발생)
function throwError(): never {
  throw new Error('Error!');
}

5. 유니언, 튜플, 리터럴 타입 활용


📌5-1. 유니언 타입 (A | B)

  • 다양한 입력 허용(여러 타입 허용).
let input: string | number;
input = 'hello';
input = 123;
  • 타입 가드로 분기 처리.
function printId(id: string | number) {
  if (typeof id === 'string') {
    console.log(id.toUpperCase());
  } else {
    console.log(id);
  }
}

📌5-2. 튜플 타입

  • 고정된 개수/타입의 배열
let tuple: [number, string] = [1, 'one'];
  • useState에서 튜플 구조 활용.
const [count, setCount]: [number, React.Dispatch<React.SetStateAction<number>>] = useState(0);

📌5-3. 리터럴 타입

  • 특정 문자열이나 숫자 값만 허용하는 타입.
type Direction = 'left' | 'right' | 'up' | 'down';

function move(dir: Direction) {
  console.log(`Moving ${dir}`);
}

move('left'); // ✅
// move('forward'); // ❌ Error
  • Button 컴포넌트의 variant: 'primary' | 'secondary' 사례
type ButtonVariant = 'primary' | 'secondary';

6. 타입 추론 vs 명시적 선언


📌6-1. 타입 추론 (Type Inference)

  • Type Inference: 명시하지 않아도 초기값이나 컨텍스트로부터 타입 유추 가능.
let name = 'TS'; // string으로 추론
let count = 10; // number로 추론
  • 언제 사용?
    • 단순 변수, 명확한 값에는 추론을 활용해 코드가 간결해집니다.

📌6-2. 명시적 선언 (Explicit Typing)

  • 복잡한 로직, 함수 시그니처, 외부 데이터 등에는 명시 필요:
function getUser(id: number): { id: number; name: string } {
  return { id, name: 'Alice' };
}
  • 팀 프로젝트, 라이브러리 개발 등에서는 명시적 선언이 일관성을 높여줍니다.

📌6-3. 추천 사용 전략.

  • 단순한 경우엔 타입 추론, 복잡하거나 명확성이 필요한 곳엔 명시적 선언을 권장합니다.

  • 함수, 객체 리턴, 외부 데이터 등에는 명시적 선언이 좋습니다.

  • 팀 내 규칙을 정해 일관된 사용 패턴을 유지하는 것이 중요합니다.

0개의 댓글