TypeScript는 Microsoft가 개발한 JavaScript의 엄격하게 타입이 지정된 슈퍼셋입니다. 타입 시스템, 인터페이스, 제네릭, 데코레이터를 추가하며 기존 JS 코드와 완벽한 호환성을 유지합니다. 컴파일 시점의 타입 검사를 통해 TypeScript는 React Native, Angular 및 기타 프레임워크에서 발생하는 오류의 전체 클래스를 방지합니다. State of JS Survey(2025)에 따르면, 설문에 응한 개발자의 78%가 TypeScript를 사용합니다. 자세한 내용은 TypeScript 문서를 참조하세요.
주요 포인트
TypeScript는 Microsoft(2012)의 프로그래밍 언어로, Anders Hejlsberg(C# 및 Turbo Pascal의 창시자)가 만들었습니다. TypeScript는 JavaScript를 정적 타입 시스템, 인터페이스, 제네릭, 열거형, 데코레이터로 확장합니다. TS 코드는 tsc 컴파일러 또는 Babel을 통해 순수 JavaScript(트랜스파일)로 컴파일됩니다 — 출력물은 모든 환경에서 실행되는 표준 JS입니다.
TypeScript를 만든 동기는 대규모 프로젝트에서 JavaScript의 한계 때문입니다. JS의 동적 타입 지정은 런타임에서만 발견되는 오류(undefined is not a function, Cannot read property of null)로 이어집니다. TypeScript는 타입 검사를 컴파일 시점으로 이동시켜 코드 실행 전에 이러한 오류를 방지합니다. 프로젝트가 클수록 TS의 이점은 더 커집니다. 10만 줄 이상의 코드베이스에서 TS는 수백 개의 잠재적 버그를 방지합니다.
TypeScript의 핵심 기능은 tsconfig.json의 선택적 strict: true 플래그를 통한 엄격한 타입 지정입니다. 엄격 모드는 모든 검사를 활성화합니다: strictNullChecks(null/undefined를 다른 타입과 호환되지 않게 함), noImplicitAny(암시적 any 금지), strictFunctionTypes(함수 매개변수의 반공변성). 기본적으로 모든 새 프로젝트에는 strict: true가 권장됩니다.
TypeScript는 개발 시점에만 JavaScript와 다릅니다. 컴파일 후 타입이 지워지며 — 런타임은 성능 저하 없이 일반 JS를 실행합니다. 이는 트레이드오프입니다: 개발에 추가 컴파일 단계가 필요하지만, IDE 자동 완성, 심볼 이름 변경을 통한 리팩토링, 코드 내 직접 타입 문서화를 제공합니다.
| 측면 | JavaScript | TypeScript |
|---|---|---|
| 타입 지정 | 동적, 런타임 | 정적, 컴파일 시점 |
| 파일 확장자 | .js | .ts(React는 .tsx) |
| 타입 오류 | 런타임에 발견 | 실행 전에 발견 |
| 제네릭 | 없음 | 있음(Generic types) |
| 인터페이스 | 없음(JSDoc만) | 있음(interface + type) |
| 컴파일 | 필요 없음 | 필요함(tsc / Babel) |
TypeScript의 타입 시스템은 구조적이며 명목적이 아닙니다: 두 타입은 이름과 관계없이 구조가 일치하면 호환됩니다. 이는 호환성이 클래스 또는 인터페이스 이름에 의해 결정되는 Java/C#과 다릅니다. 구조적 타입 지정은 기존 JS 코드와의 통합을 단순화합니다 — 모든 타입에 대해 implements를 선언할 필요가 없습니다.
TypeScript는 JS 기본 타입에 더해 다음을 지원합니다: any(검사 비활성화), unknown(안전한 any — 사용 전 검사 필요), never(반환하지 않음), void(반환값 없음), tuple(고정 길이 튜플), enum(열거형), union(string | number), intersection(A & B), literal('red' | 'blue'), index signature([key: string]: number).
// TypeScript 기본 타입 시스템
// 기본 타입
const name: string = 'React Native';
const version: number = 0.73;
const isReady: boolean = true;
// Union 및 Literal 타입
type Platform = 'ios' | 'android' | 'web';
type Status = 'idle' | 'loading' | 'success' | 'error';
function getSDKVersion(platform: Platform): number {
switch (platform) {
case 'ios': return 17;
case 'android': return 34;
case 'web': return 2025;
}
}
// Tuple — 고정 길이 튜플
type Coordinate = [number, number];
const position: Coordinate = [55.75, 37.61];
// Enum — 자동 증가 열거형
enum AppState {
Background,
Foreground,
Inactive
}
// Unknown — any의 안전한 대안
function parseJSON(json: string): unknown {
return JSON.parse(json);
}
const data = parseJSON('{"name":"TS"}');
if (typeof data === 'object' && data !== null) {
console.log((data as Record<string, unknown>).name);
}Platform 타입은 문자열 리터럴의 유니온으로, 값을 세 가지 옵션으로 제한합니다. 'windows'를 전달하면 TypeScript가 오류를 발생시킵니다. Coordinate 튜플은 정확히 두 개의 숫자를 보장합니다 — 좌표나 RGB 색상에 유용합니다. AppState 열거형은 역방향 매핑이 있는 객체로 컴파일됩니다. Unknown은 사용 전 타입 검사를 강제합니다 — any와 달리 unknown은 기본적으로 안전합니다.
인터페이스와 타입 별칭은 TypeScript에서 객체 형태를 설명합니다. 인터페이스는 선언 병합(재선언 시 필드 추가)과 확장(extends)을 지원합니다. 타입 별칭은 유니온, 교차, 튜플 및 조건부 타입을 설명할 수 있지만 선언 병합은 지원하지 않습니다. 규칙: API 객체에는 interface를, 나머지에는 type을 사용하세요.
// React Native용 인터페이스 및 타입
// 선택적 필드가 있는 인터페이스
interface User {
id: string;
name: string;
email: string;
avatar?: string; // 선택적 필드
readonly createdAt: Date; // 읽기 전용
}
// 인터페이스 확장(extends)
interface AdminUser extends User {
role: 'admin';
permissions: string[];
}
// API 데이터용 타입
type ApiResponse<T> = {
data: T;
status: Status;
error?: string;
};
// Utility types — Partial은 모든 필드를 선택적으로 만듦
type PartialUser = Partial<User>;
// Pick — 지정된 필드 선택
type UserPreview = Pick<User, 'id' | 'name' | 'avatar'>;
// Record — 타입 지정된 키가 있는 사전
type UserMap = Record<string, User>;User 인터페이스는 ?(선택적 필드)와 readonly(읽기 전용)를 가집니다. ApiResponse<T>는 API 응답을 위한 제네릭 인터페이스입니다. Partial<User>는 모든 필드를 선택적으로 만드는 유틸리티 타입입니다(편집 폼에 유용). Pick<User, 'id' | 'name'>는 지정된 필드만 선택합니다 — 미리보기 컴포넌트에 편리합니다. Record<string, User>는 ID별 사용자 사전입니다.
제네릭은 TypeScript의 핵심 기능으로, 타입 안전성을 잃지 않고 모든 타입에서 작동하는 컴포넌트를 만들 수 있게 합니다. 제네릭 함수는 꺾쇠괄호 안에 타입 매개변수로 정의됩니다: function identity<T>(arg: T): T. 타입 T는 인수에서 자동으로 추론되거나 명시적으로 지정됩니다: identity<string>('hello').
유틸리티 타입은 타입 변환을 위한 내장 제네릭입니다: Partial<T>(모든 필드 선택적), Required<T>(모든 필드 필수), Readonly<T>(모든 필드 읽기 전용), Pick<T, K>(필드 선택), Omit<T, K>(필드 제외), Record<K, T>(사전), Exclude<T, U>(유니온에서 제외), Extract<T, U>(유니온에서 추출), NonNullable<T>(null/undefined 제외).
// TypeScript의 제네릭
// API 작업을 위한 제네릭 함수
async function fetchData<T>(url: string): Promise<T> {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`HTTP ${response.status}`);
}
return response.json() as Promise<T>;
}
// 특정 타입과 함께 사용
interface Product {
id: number;
title: string;
price: number;
}
const products = await fetchData<Product[]>('/api/products');
// 상태 관리를 위한 제네릭 클래스
class StateManager<S> {
private state: S;
constructor(initial: S) {
this.state = initial;
}
getState(): S {
return this.state;
}
updateState(partial: Partial<S>): void {
this.state = { ...this.state, ...partial };
}
}
// Redux Reducer와의 타입 지정된 작업
type Action<T, P> = {
type: T;
payload: P;
};
type UserAction =
| Action<'SET_USER', User>
| Action<'CLEAR_USER', undefined>
| Action<'UPDATE_USER', Partial<User>>;fetchData<T> 함수는 fetch의 타입 지정된 래퍼입니다. 매개변수 T는 응답 형태를 결정합니다: fetchData<Product[]>를 호출하면 TypeScript는 반환된 배열에 Product 객체가 포함됨을 알게 됩니다. StateManager<S> 클래스는 모든 타입의 상태를 관리합니다 — Partial<S>는 부분 업데이트용입니다. Action<T, P>는 switch에서 자동 타입 좁히기가 있는 Redux 액션용 판별 유니온입니다.
React Native에서의 TypeScript는 컴포넌트 props와 state에 엄격한 타입 지정을 제공합니다. React Native CLI는 .tsx 확장자와 tsconfig.json이 포함된 템플릿을 생성합니다. PropTypes(JS)는 TypeScript 인터페이스로 대체되며 — 검사는 런타임이 아닌 컴파일 시점에 수행됩니다. styled-components와 React Navigation은 완전한 타입 지원을 제공합니다.
React.FC<Props>는 props가 있는 함수형 컴포넌트의 타입입니다. children은 자동으로 타입이 지정됩니다. useRef<T> — 네이티브 컴포넌트에 대한 참조. useState<S> — 타입 추론을 통한 상태 관리. useNavigation<T> — 타입 지정된 네비게이션. useCallback, useMemo — 자동 타입 추론 포함. 모든 React 훅은 완전히 타입 지정되어 있습니다.
// 타입 지정된 React Native 컴포넌트
import React, { useState, useCallback } from 'react';
import {
View, Text, FlatList, TouchableOpacity,
StyleSheet
} from 'react-native';
import { useNavigation } from '@react-navigation/native';
import { NativeStackNavigationProp } from '@react-navigation/native-stack';
// 네비게이션 및 데이터용 타입
type RootStackParamList = {
Home: undefined;
Profile: { userId: string };
Settings: undefined;
};
type NavigationProp =
NativeStackNavigationProp<RootStackParamList, 'Home'>;
// props용 인터페이스
interface ProductListProps {
products: Product[];
onSelect: (id: number) => void;
}
// 타입 지정된 함수형 컴포넌트
const ProductList: React.FC<ProductListProps> = ({
products,
onSelect
}) => {
const navigation = useNavigation<NavigationProp>();
const [selectedId, setSelectedId] = useState<number | null>(null);
const handlePress = useCallback((id: number) => {
setSelectedId(id);
onSelect(id);
navigation.navigate('Profile', { userId: String(id) });
}, [onSelect, navigation]);
const renderItem = useCallback(({ item }: { item: Product }) => (
<TouchableOpacity onPress={() => handlePress(item.id)}>
<Text>{item.title}</Text>
<Text>${item.price.toFixed(2)}</Text>
</TouchableOpacity>
), [handlePress]);
return (
<FlatList
data={products}
renderItem={renderItem}
keyExtractor={(item) => String(item.id)}
/>
);
};RootStackParamList 타입은 해당 매개변수가 있는 라우트의 사전입니다. NavigationProp은 타입 지정된 네비게이션을 제공합니다: navigation.navigate('Profile', { userId })는 Profile이 userId를 받아들임을 확인합니다. 타입 지정된 매개변수가 있는 useCallback은 불필요한 리렌더링을 방지합니다. FlatList는 제네릭을 통해 타입이 지정됩니다:
TypeScript 도구에는 tsc 컴파일러, tsconfig.json, VS Code의 IDE 지원, @typescript-eslint를 사용한 ESLint, Prettier 및 DefinitelyTyped(@types/*)가 포함됩니다. tsc는 .ts를 .js로 변환하는 컴파일러입니다. tsconfig.json은 다음을 구성합니다: target(ES2020), module(ESNext), strict: true, outDir(출력 폴더). sourceMap — 코드 맵을 통한 브라우저에서의 TS 디버깅.
DefinitelyTyped는 내장 타입이 없는 라이브러리를 위한 타입 정의 저장소입니다. 설치: npm install @types/react @types/react-native --save-dev. .d.ts 파일은 타입 선언입니다. 최신 라이브러리(React, React Native, Angular)는 내장 타입을 포함하며 @types/가 필요하지 않습니다. 오래된 JS 라이브러리의 경우 DefinitelyTyped가 유일한 타입 소스입니다.
// tsconfig.json — 최소 구성
{
"compilerOptions": {
"target": "esnext",
"module": "commonjs",
"strict": true,
"jsx": "react-native",
"moduleResolution": "node",
"allowSyntheticDefaultImports": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"noEmit": true // 검사만, JS 생성 안 함
},
"include": ["src/**/*.ts", "src/**/*.tsx"],
"exclude": ["node_modules", "babel.config.js"]
}strict: true 옵션은 모든 타입 검사를 활성화합니다 — 모든 프로젝트에 권장. jsx: 'react-native'는 변환 없이 JSX를 유지합니다(React Native는 Babel을 통해 JSX를 처리). moduleResolution: 'node' — Node.js와 같은 모듈 해석. esModuleInterop — CommonJS 모듈과의 호환성. noEmit: true — JS 파일을 생성하지 않고 검사만 수행(Babel 또는 Metro가 JS를 생성).
자주 묻는 질문
TypeScript는 Microsoft(2012)의 JavaScript에 대한 엄격하게 타입이 지정된 슈퍼셋입니다. 정적 타입 지정, 인터페이스, 제네릭, 열거형, 데코레이터를 추가합니다. tsc를 통해 순수 JS로 컴파일됩니다. 모든 JS 코드와 호환됩니다. React Native(신규 프로젝트의 ~65%), Angular 및 Node.js에서 사용됩니다. Anders Hejlsberg(C# 창시자)가 만들었습니다.
TypeScript는 React 컴포넌트의 props와 state에 엄격한 타입 지정을 제공합니다 — 타입 오류는 런타임이 아닌 컴파일 시점에 발견됩니다. IDE 자동 완성이 모든 라이브러리에서 작동합니다. 제네릭은 복잡한 구조(Redux store, API)를 타입 지정합니다. React Navigation은 완전한 라우트 타입 지정을 제공합니다. 설문에 따르면 JS 개발자의 78%가 TypeScript를 사용합니다.
tsc 컴파일러가 .ts/.tsx 파일을 파싱하고, 타입을 검사하고, 주석을 제거하고 .js를 생성합니다. 대상(ES5, ES2020)은 tsconfig.json에서 설정됩니다. TypeScript는 런타임을 변경하지 않으며 — 지워진 타입은 성능에 영향을 주지 않습니다. 소스 맵은 디버깅을 위해 컴파일된 JS를 원본 TS와 연결합니다. @babel/preset-typescript를 사용한 Babel은 tsc의 대안입니다.
TypeScript는 모든 JS 타입을 포함합니다: string, number, boolean, null, undefined, symbol, any. 다음을 추가합니다: void, never, unknown, tuple, enum, union(string | number), intersection(A & B), literal('red' | 'blue'), Record, Pick, Omit, Partial, Required, Readonly, Extract, Exclude, NonNullable. 제네릭은 일반화된 타입을 만듭니다: Array<number>, Promise<string>, Map<string, User>.
tsc 컴파일러는 typescript npm 패키지에 포함되어 있습니다. VS Code — 기본 TS 지원, 자동 완성, 리팩토링이 되는 IDE. tsconfig.json은 엄격 모드를 구성합니다. @typescript-eslint/parser를 사용한 ESLint — 정적 분석. Prettier — 포맷팅. DefinitelyTyped(@types/*) — 내장 지원이 없는 라이브러리용 타입. React Native CLI에는 TypeScript 템플릿이 포함되어 있습니다.
요약
턴키 방식의 모바일 애플리케이션을 개발해 드립니다
IT Sectr는 2017년부터 스타트업과 기업을 위한 iOS 및 Android 애플리케이션을 만듭니다. 저희가 상담해 드리고 최적의 솔루션을 제안하겠습니다.