목 차
1. JS vs TS의 차이.
2. TypeScript를 쓰는 이유: 안정성과 예측 가능성
3. React Native에서 TypeScript 적용 장점.
4. TypeScript 기본 타입 정리.
5. 유니언, 튜플, 리터럴 타입 활용
6. 타입 추론 vs 명시적 선언
JavaScript (JS)
TypeScript (TS)
작은 프로젝트에서는 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; // 타입 불일치 시 컴파일 에러 발생
}
정적 타입 vs 동적 타입
컴파일 타임 체크 vs 런타임 에러
인터페이스, 제네릭, 열거형 등 TS 고급 문법.
타입 기반 개발 → 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}`);
}
VSCode 기반 자동완성 & IntelliSense 강화
TSLint / ESLint + TypeScript 지원
React Native와의 자연스러운 통합
Expo + TypeScript: npx create-expo-app --template
개발 초기 세팅 시부터 TS 도입 권장
ESLint, Prettier와 함께 사용하면 코드 일관성과 품질 확보
npx create-expo-app MyApp --template
// App.tsx
export default function App() {
return <Text>Hello TypeScript</Text>;
}
API 통신, Native 모듈과의 브리징에서 타입을 통해 오류 방지.
팀원 간 타입 명세를 기반으로 안전한 인터페이스 공유 가능.
interface Product {
id: number;
name: string;
price: number;
}
function printProduct(p: Product) {
console.log(`${p.name}: $${p.price}`);
}
// 실수로 price를 string으로 넘기면 컴파일 에러 발생
타입 기반 API 설계(API 명세화 효과)
함수 입력/출력 명확성
리팩토링 시 코드 붕괴 방지(리팩토링에 강함)
Context, Reducer 등의 구조적 설계와 잘 맞음
Editor Integration: 타입 기반 자동완성과 오류 탐지 제공
Type as Documentation : 타입은 곧 문서
interface ButtonProps {
label: string;
onPress: () => void;
variant?: 'primary' | 'secondary';
}
const Button: React.FC<ButtonProps> = ({ label, onPress, variant = 'primary' }) => {
// variant 값에 따라 스타일 분기 가능
};
Props/State 명시적 타입 지정:
props의 타입을 명확히 하여 불필요한 런타임 에러 방지
Props에 타입을 부여하여 자동완성과 타입 보호를 동시에 확보.
컴포넌트 재사용 시 타입 기준으로 명세화가 되어 있음.
불필요한 런타임 에러 방지
interface AvatarProps {
uri: string;
size?: number;
}
const Avatar = ({ uri, size = 50 }: AvatarProps) => {
return <Image source={{ uri }} style={{ width: size, height: size }} />;
};
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);
};
API 응답 데이터의 타입을 지정해 파싱 에러 방지
Axios나 react-query와 함께 사용하여 응답 데이터에 대한 타입 안전성 확보
interface UserResponse {
id: number;
name: string;
}
const fetchUser = async (): Promise<UserResponse> => {
const { data } = await axios.get('/user');
return data;
};
스타일 객체의 타입 안정성:
@types를 통해 외부 라이브러리 안정성 확보
import styled from 'styled-components/native';
const StyledText = styled.Text<{ color: string }>`
color: ${(props) => props.color};
`;
타입 기반으로 코드 흐름이 명확하여 디버깅이 쉬움
타입 정보 덕분에 유닛 테스트 작성 시 예상 입력값 명확
Jest나 Detox 테스트에서 함수의 예상 입력값을 명확히 알 수 있어 테스트 작성이 용이.
// 테스트 대상 함수
function sum(a: number, b: number): number {
return a + b;
}
// Jest 테스트
it('adds two numbers', () => {
expect(sum(1, 2)).toBe(3);
});
let name: string = 'TypeScript';
let age: number = 10;
let isActive: boolean = true;
function greet(name: string): string {
return `Hello, ${name}`;
}
let value: any = 10;
value = 'hello'; // 에러 없음
let value: unknown = 10;
// value.toFixed(2); // 에러! number인지 확인 필요
function log(message: string): void {
console.log(message);
}
function throwError(): never {
throw new Error('Error!');
}
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);
}
}
let tuple: [number, string] = [1, 'one'];
const [count, setCount]: [number, React.Dispatch<React.SetStateAction<number>>] = useState(0);
type Direction = 'left' | 'right' | 'up' | 'down';
function move(dir: Direction) {
console.log(`Moving ${dir}`);
}
move('left'); // ✅
// move('forward'); // ❌ Error
type ButtonVariant = 'primary' | 'secondary';
let name = 'TS'; // string으로 추론
let count = 10; // number로 추론
function getUser(id: number): { id: number; name: string } {
return { id, name: 'Alice' };
}
단순한 경우엔 타입 추론, 복잡하거나 명확성이 필요한 곳엔 명시적 선언을 권장합니다.
함수, 객체 리턴, 외부 데이터 등에는 명시적 선언이 좋습니다.
팀 내 규칙을 정해 일관된 사용 패턴을 유지하는 것이 중요합니다.