React Native์™€ TypeScript 2026: ํƒ€์ž… ์•ˆ์ „ํ•œ ์•„ํ‚คํ…์ฒ˜์™€ ๋ฉด์ ‘ ์งˆ๋ฌธ

2026๋…„ React Native์—์„œ TypeScript๋ฅผ ํ™œ์šฉํ•œ ํƒ€์ž… ์•ˆ์ „ ์•„ํ‚คํ…์ฒ˜๋ฅผ ๋‹ค๋ฃน๋‹ˆ๋‹ค. Codegen, TurboModules, Strict TypeScript API, ํƒ€์ž… ์•ˆ์ „ ๋‚ด๋น„๊ฒŒ์ด์…˜, ๋ฉด์ ‘ ์งˆ๋ฌธ์„ ์ฝ”๋“œ ์˜ˆ์ œ์™€ ํ•จ๊ป˜ ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค.

React Native TypeScript ํƒ€์ž… ์•ˆ์ „ ์•„ํ‚คํ…์ฒ˜์™€ ์ฝ”๋“œ, ๋ชจ๋ฐ”์ผ ๋””๋ฐ”์ด์Šค

2026๋…„ ์ค‘๋ฐ˜ ํ˜„์žฌ, React Native์—์„œ TypeScript ํƒ€์ž… ์•ˆ์ „์„ฑ์€ ํฌ๊ฒŒ ์„ฑ์ˆ™ํ•œ ๋‹จ๊ณ„์— ์ด๋ฅด๋ €์Šต๋‹ˆ๋‹ค. ๋ฒ„์ „ 0.86์—์„œ๋Š” React 19.1, Strict TypeScript API, ๊ทธ๋ฆฌ๊ณ  Codegen ๊ธฐ๋ฐ˜์˜ ์™„์ „ํ•œ ๋ธŒ๋ฆฌ์ง€๋ฆฌ์Šค ์•„ํ‚คํ…์ฒ˜๊ฐ€ ๊ธฐ๋ณธ์œผ๋กœ ํƒ‘์žฌ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. TypeScript๋Š” ๋” ์ด์ƒ JavaScript์™€ ๋„ค์ดํ‹ฐ๋ธŒ ์ฝ”๋“œ ์‚ฌ์ด๋ฅผ ์—ฐ๊ฒฐํ•˜๋Š” ์„ ํƒ์  ๋„๊ตฌ๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค. ์ปดํฌ๋„ŒํŠธ props์—์„œ TurboModule ์ธํ„ฐํŽ˜์ด์Šค์— ์ด๋ฅด๊ธฐ๊นŒ์ง€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ „์ฒด์˜ ๊ณ„์•ฝ์„ ์ฃผ๋„ํ•˜๋ฉฐ, ํ”„๋กœ๋•์…˜ ํฌ๋ž˜์‹œ ๋กœ๊ทธ๊ฐ€ ์•„๋‹Œ ๋นŒ๋“œ ์‹œ์ ์— ๋ถˆ์ผ์น˜๋ฅผ ๊ฐ์ง€ํ•˜๋Š” ๊ตฌ์กฐ๋กœ ๋ฐœ์ „ํ–ˆ์Šต๋‹ˆ๋‹ค.

2026๋…„ ์ฃผ์š” ๋ณ€๊ฒฝ ์‚ฌํ•ญ

React Native 0.80์—์„œ ์˜ตํŠธ์ธ ๋ฐฉ์‹์˜ Strict TypeScript API๊ฐ€ ๋„์ž…๋˜์—ˆ๊ณ , 0.82์—์„œ ๋ ˆ๊ฑฐ์‹œ ๋ธŒ๋ฆฌ์ง€๊ฐ€ ์™„์ „ํžˆ ์ œ๊ฑฐ๋˜์—ˆ์œผ๋ฉฐ, 0.85์—์„œ ๋งˆ์ง€๋ง‰ interop ๋ ˆ์ด์–ด๊ฐ€ ์‚ญ์ œ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. 2026๋…„ 6์›” ๊ธฐ์ค€ 0.86์—์„œ๋Š” ๋ชจ๋“  ์ƒˆ ํ”„๋กœ์ ํŠธ๊ฐ€ ์†Œ์Šค ์ฝ”๋“œ์—์„œ ์ง์ ‘ ์ƒ์„ฑ๋œ TypeScript ํƒ€์ž…์„ ์‚ฌ์šฉํ•˜์—ฌ ์™„์ „ํ•œ ๋ธŒ๋ฆฌ์ง€๋ฆฌ์Šค ๊ตฌ์„ฑ์œผ๋กœ ์‹œ์ž‘๋ฉ๋‹ˆ๋‹ค.

TypeScript๊ฐ€ React Native์˜ ๊ธฐ๋ณธ๊ฐ’์ด ๋œ ์ด์œ 

๋ฒ„์ „ 0.76 ์ดํ›„๋กœ npx react-native init ๋ช…๋ น์–ด๋กœ ์ƒ์„ฑ๋˜๋Š” ๋ชจ๋“  ํ”„๋กœ์ ํŠธ๋Š” TypeScript๋กœ ๊ตฌ์„ฑ๋ฉ๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ๋ณธ์งˆ์ ์ธ ๋ณ€ํ™”๋Š” ๋„ค์ดํ‹ฐ๋ธŒ ๊ฒฝ๊ณ„์—์„œ ์ผ์–ด๋‚ฌ์Šต๋‹ˆ๋‹ค. Codegen ๋„์ž… ์ด์ „์— ๊ฐœ๋ฐœ์ž๋“ค์€ JavaScript์—์„œ Objective-C๋‚˜ Kotlin์œผ๋กœ์˜ ๊ฒฝ๊ณ„๋ฅผ ๋„˜์„ ๋•Œ ์ˆ˜๋™ ํƒ€์ž… ์–ด์„ค์…˜์„ ์ž‘์„ฑํ•ด์•ผ ํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ๋ฌธ์ž์—ด ๊ธฐ๋ฐ˜์˜ ์•”๋ฌต์  ๊ณ„์•ฝ์ด์—ˆ๊ณ , ๋Ÿฐํƒ€์ž„์— ์กฐ์šฉํžˆ ๊นจ์ง€๋Š” ๋ฌธ์ œ๋ฅผ ์ผ์œผ์ผฐ์Šต๋‹ˆ๋‹ค.

Codegen์€ TypeScript ์‚ฌ์–‘ ํŒŒ์ผ์„ ์ฝ์–ด C++, Objective-C++, Java/Kotlin ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ž๋™์œผ๋กœ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. TypeScript ์‚ฌ์–‘์ด number๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋ฉ”์„œ๋“œ๋ฅผ ์„ ์–ธํ•˜๋ฉด, ์ƒ์„ฑ๋œ ๋„ค์ดํ‹ฐ๋ธŒ ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ํ•ด๋‹น ์ œ์•ฝ ์กฐ๊ฑด์„ ์ปดํŒŒ์ผ ์‹œ์ ์— ๊ฐ•์ œํ•ฉ๋‹ˆ๋‹ค.

React Native ๊ณต์‹ ๋ฌธ์„œ์—์„œ๋Š” ๊ธฐ๋ณธ์ ์ธ ์„ค์ •์„ ๋‹ค๋ฃจ๊ณ  ์žˆ์ง€๋งŒ, ํ”„๋กœ๋•์…˜ ํ™˜๊ฒฝ์—์„œ ์ค‘์š”ํ•œ ํƒ€์ž… ์•ˆ์ „ ํŒจํ„ด์€ ๊ทธ ์ด์ƒ์ž…๋‹ˆ๋‹ค. ํƒ€์ž… ์•ˆ์ „ ๋‚ด๋น„๊ฒŒ์ด์…˜ ์Šคํƒ, ์ œ๋„ค๋ฆญ API ํ›…, ์ƒํƒœ ๋จธ์‹ ์šฉ ํŒ๋ณ„ ์œ ๋‹ˆ์˜จ, Codegen ๊ธฐ๋ฐ˜ TurboModule ์‚ฌ์–‘์ด ํ•ต์‹ฌ์„ ์ด๋ฃน๋‹ˆ๋‹ค.

Strict TypeScript API ์„ค์ •

React Native 0.80์—์„œ ๋„์ž…๋œ Strict TypeScript API๋Š” ์†Œ์Šค ์ฝ”๋“œ์—์„œ ์ง์ ‘ ์ƒ์„ฑ๋œ ํƒ€์ž…์œผ๋กœ๋งŒ ๊ณต๊ฐœ API ํ‘œ๋ฉด์„ ์ œํ•œํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ๋งˆ์ด๋„ˆ ๋ฒ„์ „ ๊ฐ„์— ๊นจ์งˆ ์ˆ˜ ์žˆ๋Š” ๋‚ด๋ถ€ ๋ชจ๋“ˆ์— ๋Œ€ํ•œ ์‹ค์ˆ˜๋กœ ์ธํ•œ ์˜์กด์„ ๋ฐฉ์ง€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

tsconfig.jsonjson
{
  "compilerOptions": {
    "strict": true,
    "exactOptionalPropertyTypes": true,
    "noUncheckedIndexedAccess": true,
    "moduleResolution": "bundler",
    "jsx": "react-jsx",
    "types": ["react-native/types/strict"]
  },
  "extends": "@react-native/typescript-config/tsconfig.json"
}

์ด ์„ค์ •์„ ์ ์šฉํ•˜๋ฉด react-native/Libraries/Text/Text์™€ ๊ฐ™์€ ํ•˜์œ„ ๊ฒฝ๋กœ์—์„œ์˜ ์ž„ํฌํŠธ๋Š” ํƒ€์ž… ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ๋ชจ๋“  ์ž„ํฌํŠธ๋Š” ๋ฃจํŠธ react-native ํŒจํ‚ค์ง€์—์„œ ์ด๋ฃจ์–ด์ ธ์•ผ ํ•˜๋ฉฐ, 0.80๋ถ€ํ„ฐ ๊ฐ•์ œ๋œ ๋”ฅ ์ž„ํฌํŠธ ์ง€์› ์ค‘๋‹จ ์ •์ฑ…์— ๋ถ€ํ•ฉํ•ฉ๋‹ˆ๋‹ค.

React Navigation 7์„ ํ™œ์šฉํ•œ ํƒ€์ž… ์•ˆ์ „ ๋‚ด๋น„๊ฒŒ์ด์…˜

React Navigation 7.x๋Š” TypeScript์— ๋Œ€ํ•œ ํผ์ŠคํŠธ ํด๋ž˜์Šค ์ง€์›์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ํ•ต์‹ฌ ํŒจํ„ด์€ ๊ฐ ํ™”๋ฉด ์ด๋ฆ„๊ณผ ํ•ด๋‹น ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ๋งคํ•‘ํ•˜๋Š” RootStackParamList ํƒ€์ž…์„ ์ •์˜ํ•˜๊ณ , ํ•ด๋‹น ํƒ€์ž…์„ ๋„ค๋น„๊ฒŒ์ดํ„ฐ์™€ ํ™”๋ฉด ์ปดํฌ๋„ŒํŠธ์— ์ „ํŒŒํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

navigation/types.tstypescript
export type RootStackParamList = {
  Home: undefined;
  Profile: { userId: string };
  Settings: undefined;
  ArticleDetail: { articleId: string; source: 'feed' | 'search' };
};

export type AppTabParamList = {
  Dashboard: undefined;
  Explore: { category?: string };
  Notifications: undefined;
};

ํ™”๋ฉด ์ปดํฌ๋„ŒํŠธ๋Š” ์ˆ˜๋™ ์บ์ŠคํŒ… ์—†์ด ํƒ€์ž…์ด ์ง€์ •๋œ props๋ฅผ ๋ฐ›์Šต๋‹ˆ๋‹ค.

screens/ArticleDetailScreen.tsxtypescript
import type { NativeStackScreenProps } from '@react-navigation/native-stack';
import type { RootStackParamList } from '../navigation/types';

type Props = NativeStackScreenProps<RootStackParamList, 'ArticleDetail'>;

export function ArticleDetailScreen({ route, navigation }: Props) {
  // route.params.articleId๋Š” string โ€” ํƒ€์ž…์— ์˜ํ•ด ๋ณด์žฅ๋จ
  // route.params.source๋Š” 'feed' | 'search' โ€” ๋Ÿฐํƒ€์ž„ ๊ฒ€์‚ฌ ๋ถˆํ•„์š”
  const { articleId, source } = route.params;

  // navigation.navigate('Profile', { userId: '123' }) โ€” ํƒ€์ž… ์ฒดํฌ ์™„๋ฃŒ
  // navigation.navigate('Profile', {}) โ€” ์ปดํŒŒ์ผ ์—๋Ÿฌ: userId ๋ˆ„๋ฝ
  return (
    <ArticleView id={articleId} referrer={source} />
  );
}

์ด ํŒจํ„ด์„ ํ†ตํ•ด ๋Ÿฐํƒ€์ž„ ์—๋Ÿฌ์˜ ํ•œ ๋ฒ”์ฃผ๊ฐ€ ์™„์ „ํžˆ ์ œ๊ฑฐ๋ฉ๋‹ˆ๋‹ค. ์ž˜๋ชป๋œ ํŒŒ๋ผ๋ฏธํ„ฐ ๋˜๋Š” ๋ˆ„๋ฝ๋œ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ํ™”๋ฉด ์ด๋™์„ ์‹œ๋„ํ•˜๋ฉด ์•ฑ ์‹คํ–‰ ์ „ ๋นŒ๋“œ ์‹œ์ ์— ์‹คํŒจํ•ฉ๋‹ˆ๋‹ค.

useNavigation ํ›… ํƒ€์ž… ์ง€์ •

์ง์ ‘์ ์ธ ํ™”๋ฉด ์ž์‹ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์•„๋‹Œ ๊ฒฝ์šฐ, useNavigation<NativeStackNavigationProp<RootStackParamList>>()๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด props ์ „๋‹ฌ ์—†์ด๋„ ๋™์ผํ•œ ํƒ€์ž… ์•ˆ์ „์„ฑ์„ ํ™•๋ณดํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Codegen์„ ํ™œ์šฉํ•œ ํƒ€์ž… ์•ˆ์ „ TurboModule ๊ตฌ์ถ•

TurboModules๋Š” ๊ธฐ์กด Native Modules ์‹œ์Šคํ…œ์„ ๋Œ€์ฒดํ•ฉ๋‹ˆ๋‹ค. TypeScript ์‚ฌ์–‘ ํŒŒ์ผ์ด ๋‹จ์ผ ์ •๋ณด ์ถœ์ฒ˜(single source of truth)๋กœ ๊ธฐ๋Šฅํ•˜๋ฉฐ, Codegen์ด ์ด๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ๋„ค์ดํ‹ฐ๋ธŒ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. ์‚ฌ์–‘๊ณผ ๋„ค์ดํ‹ฐ๋ธŒ ๊ตฌํ˜„์ด ์ผ์น˜ํ•˜์ง€ ์•Š์œผ๋ฉด ๋นŒ๋“œ๊ฐ€ ์‹คํŒจํ•ฉ๋‹ˆ๋‹ค.

specs/NativeDeviceInfo.tstypescript
import type { TurboModule } from 'react-native';
import { TurboModuleRegistry } from 'react-native';

export interface Spec extends TurboModule {
  getDeviceModel(): string;
  getBatteryLevel(): Promise<number>;
  getStorageInfo(): Promise<{
    totalBytes: number;
    freeBytes: number;
    usedPercentage: number;
  }>;
  onBatteryChange(callback: (level: number) => void): void;
}

export default TurboModuleRegistry.getEnforcing<Spec>('DeviceInfo');

npx react-native codegen์„ ์‹คํ–‰ํ•˜๋ฉด ๋Œ€์‘ํ•˜๋Š” C++, Objective-C++, Java ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค. ๋„ค์ดํ‹ฐ๋ธŒ ๊ตฌํ˜„์€ ๋ชจ๋“  ๋ฉ”์„œ๋“œ ์‹œ๊ทธ๋‹ˆ์ฒ˜์™€ ์ •ํ™•ํžˆ ์ผ์น˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด getStorageInfo๋Š” 3๊ฐœ์˜ ์ˆซ์ž ํ•„๋“œ๋ฅผ ๊ฐ€์ง„ ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•ด์•ผ ํ•˜๋ฉฐ, ๋‹ค๋ฅธ ๊ตฌ์กฐ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋ฉด ๋„ค์ดํ‹ฐ๋ธŒ ์ธก์—์„œ ์ปดํŒŒ์ผ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

android/app/src/main/java/com/app/DeviceInfoModule.ktkotlin
class DeviceInfoModule(reactContext: ReactApplicationContext) :
    NativeDeviceInfoSpec(reactContext) {

    // ๋ฐ˜ํ™˜ ํƒ€์ž…์€ ์ƒ์„ฑ๋œ NativeDeviceInfoSpec์— ์˜ํ•ด ๊ฐ•์ œ๋จ
    override fun getDeviceModel(): String {
        return Build.MODEL
    }

    override fun getBatteryLevel(): Promise<Double> {
        val bm = reactContext.getSystemService(Context.BATTERY_SERVICE)
            as BatteryManager
        val level = bm.getIntProperty(
            BatteryManager.BATTERY_PROPERTY_CAPACITY
        ).toDouble()
        return Promise.resolve(level)
    }
}

๊ธฐ์กด ์•„ํ‚คํ…์ฒ˜์—์„œ ๋ฌธ์ œ๊ฐ€ ๋˜์—ˆ๋˜ ReadableMap๊ณผ NSDictionary ํŒŒ์‹ฑ์œผ๋กœ ์ธํ•œ ์•”๋ฌต์  ํƒ€์ž… ๋ณ€ํ™˜ ๋ฒ„๊ทธ๊ฐ€ ์ด ์ ‘๊ทผ ๋ฐฉ์‹์„ ํ†ตํ•ด ์ œ๊ฑฐ๋ฉ๋‹ˆ๋‹ค.

React Native ๋ฉด์ ‘ ์ค€๋น„๊ฐ€ ๋˜์…จ๋‚˜์š”?

์ธํ„ฐ๋ž™ํ‹ฐ๋ธŒ ์‹œ๋ฎฌ๋ ˆ์ดํ„ฐ, flashcards, ๊ธฐ์ˆ  ํ…Œ์ŠคํŠธ๋กœ ์—ฐ์Šตํ•˜์„ธ์š”.

์ œ๋„ค๋ฆญ ํƒ€์ž…์„ ํ™œ์šฉํ•œ ํƒ€์ž… ์•ˆ์ „ API ํ›…

์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ํƒ€์ž… ํ›… ํŒจํ„ด์„ ํ†ตํ•ด ํ™”๋ฉด ๊ฐ„ ํŽ˜์น˜ ๋กœ์ง ์ค‘๋ณต ์—†์ด ์™„์ „ํ•œ ํƒ€์ž… ์ถ”๋ก ์„ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

hooks/useApiQuery.tstypescript
import { useQuery, UseQueryOptions } from '@tanstack/react-query';

interface ApiResponse<T> {
  data: T;
  meta: { page: number; totalPages: number };
}

export function useApiQuery<T>(
  key: readonly string[],
  endpoint: string,
  options?: Omit<UseQueryOptions<ApiResponse<T>>, 'queryKey' | 'queryFn'>
) {
  return useQuery<ApiResponse<T>>({
    queryKey: key,
    queryFn: async () => {
      const response = await fetch(`${API_BASE}${endpoint}`);
      if (!response.ok) throw new ApiError(response.status);
      return response.json() as Promise<ApiResponse<T>>;
    },
    ...options,
  });
}

// ์‚ฌ์šฉ ์˜ˆ์‹œ โ€” T๋Š” Article[]๋กœ ์ถ”๋ก ๋จ
interface Article {
  id: string;
  title: string;
  publishedAt: string;
}

const { data, isLoading } = useApiQuery<Article[]>(
  ['articles', 'latest'],
  '/articles?sort=latest'
);
// data.data๋Š” Article[] โ€” ์™„์ „ํ•œ ํƒ€์ž… ์ง€์ •
// data.meta.totalPages๋Š” number

์ œ๋„ค๋ฆญ ํŒŒ๋ผ๋ฏธํ„ฐ T๋Š” ํ›… ํ˜ธ์ถœ ์ง€์ ์—์„œ ์ฟผ๋ฆฌ ํ•จ์ˆ˜๋ฅผ ๊ฑฐ์ณ ๊ฒฐ๊ณผ๋ฅผ ์†Œ๋น„ํ•˜๋Š” ์ปดํฌ๋„ŒํŠธ๊นŒ์ง€ ์ „์ฒด ์ฒด์ธ์— ๊ฑธ์ณ ์ „ํŒŒ๋ฉ๋‹ˆ๋‹ค. as ์บ์ŠคํŒ…๋„ any ํƒ€์ž…๋„ ํ•„์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

ํŒ๋ณ„ ์œ ๋‹ˆ์˜จ์„ ํ™œ์šฉํ•œ ์ƒํƒœ ๋จธ์‹  ์„ค๊ณ„

ํ™”๋ฉด์˜ ๋ณต์žกํ•œ ์ƒํƒœ(๋กœ๋”ฉ, ์—๋Ÿฌ, ๋นˆ ์ƒํƒœ, ๋กœ๋“œ ์™„๋ฃŒ)๋Š” ์„ ํƒ์  ํ•„๋“œ์˜ ์ง‘ํ•ฉ์ด ์•„๋‹Œ ํŒ๋ณ„ ์œ ๋‹ˆ์˜จ์œผ๋กœ ๋ชจ๋ธ๋งํ•˜๋Š” ๊ฒƒ์ด ์ตœ์ ์ž…๋‹ˆ๋‹ค.

types/screen-state.tstypescript
type ScreenState<T> =
  | { status: 'idle' }
  | { status: 'loading' }
  | { status: 'error'; error: string; retryCount: number }
  | { status: 'empty'; message: string }
  | { status: 'loaded'; data: T; refreshedAt: Date };

// components/DataScreen.tsx
function renderContent<T>(state: ScreenState<T>, renderItem: (data: T) => ReactNode) {
  switch (state.status) {
    case 'idle':
      return null;
    case 'loading':
      return <LoadingSpinner />;
    case 'error':
      // state.error๋Š” ์—ฌ๊ธฐ์„œ string โ€” TypeScript๊ฐ€ ์ž๋™์œผ๋กœ ์ขํ˜€์คŒ
      return <ErrorBanner message={state.error} retries={state.retryCount} />;
    case 'empty':
      return <EmptyState message={state.message} />;
    case 'loaded':
      // state.data๋Š” T โ€” ์™„์ „ํ•œ ํƒ€์ž… ์ง€์ •
      return renderItem(state.data);
  }
}

์ด ํŒจํ„ด์„ ํ†ตํ•ด ๋ถˆ๊ฐ€๋Šฅํ•œ ์ƒํƒœ๋ฅผ ํƒ€์ž… ์ˆ˜์ค€์—์„œ ํ‘œํ˜„ ๋ถˆ๊ฐ€๋Šฅํ•˜๊ฒŒ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. loading ์ƒํƒœ๊ฐ€ ์˜ค๋ž˜๋œ data๋ฅผ ์ž˜๋ชป ๋ณด์œ ํ•  ์ˆ˜ ์—†์œผ๋ฉฐ, error ์ƒํƒœ์—๋Š” ํ•ญ์ƒ ๋””๋ฒ„๊น…์„ ์œ„ํ•œ ์ปจํ…์ŠคํŠธ๊ฐ€ ํฌํ•จ๋ฉ๋‹ˆ๋‹ค.

๋ถ€๋ถ„์  ์ƒํƒœ ๊ฐ์ฒด์˜ ํ•จ์ •

ํ”ํ•œ ์•ˆํ‹ฐํŒจํ„ด: { isLoading: boolean; error?: string; data?: T }. ์ด ์ •์˜์—์„œ๋Š” { isLoading: true, error: 'fail', data: [...] }์™€ ๊ฐ™์€ ์ƒํƒœ๊ฐ€ ํ—ˆ์šฉ๋ฉ๋‹ˆ๋‹ค โ€” ์„ธ ๊ฐ€์ง€ ๋ชจ์ˆœ๋œ ์‹ ํ˜ธ๊ฐ€ ๋™์‹œ์— ์กด์žฌํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ํŒ๋ณ„ ์œ ๋‹ˆ์˜จ์„ ์‚ฌ์šฉํ•˜๋ฉด ์ด๋Ÿฌํ•œ ์ƒํƒœ๋ฅผ ํƒ€์ž… ์ˆ˜์ค€์—์„œ ๋ฐฉ์ง€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

React Native TypeScript ๋ฉด์ ‘ ์งˆ๋ฌธ

New Architecture์™€ TypeScript๊ฐ€ ํ‘œ์ค€์ด ๋œ 2026๋…„, ์‹œ๋‹ˆ์–ด ๋ชจ๋ฐ”์ผ ์—”์ง€๋‹ˆ์–ด๋ง ํŒ€ ๋ฉด์ ‘์—์„œ ์‹ค์ œ๋กœ ์ถœ์ œ๋˜๋Š” ์งˆ๋ฌธ๋“ค์„ ๋‹ค๋ฃน๋‹ˆ๋‹ค.

Codegen์€ JavaScript-๋„ค์ดํ‹ฐ๋ธŒ ๊ฒฝ๊ณ„์—์„œ ์–ด๋–ป๊ฒŒ ํƒ€์ž… ์•ˆ์ „์„ฑ์„ ๋ณด์žฅํ•ฉ๋‹ˆ๊นŒ?

Codegen์€ TypeScript(๋˜๋Š” Flow) ์‚ฌ์–‘ ํŒŒ์ผ์„ ์ฝ์–ด C++, Objective-C++, Java/Kotlin ์ธํ„ฐํŽ˜์ด์Šค ์ฝ”๋“œ๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. ์ƒ์„ฑ๋œ ๋„ค์ดํ‹ฐ๋ธŒ ์ธํ„ฐํŽ˜์ด์Šค๋Š” ์‚ฌ์–‘์— ์ •์˜๋œ ๋ฉ”์„œ๋“œ ์‹œ๊ทธ๋‹ˆ์ฒ˜, ํŒŒ๋ผ๋ฏธํ„ฐ ํƒ€์ž…, ๋ฐ˜ํ™˜ ํƒ€์ž…์„ ์ •ํ™•ํ•˜๊ฒŒ ๊ฐ•์ œํ•ฉ๋‹ˆ๋‹ค. ๋„ค์ดํ‹ฐ๋ธŒ ๊ตฌํ˜„์ด ์ผ์น˜ํ•˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ โ€” ์‚ฌ์–‘์ด Double์„ ์„ ์–ธํ–ˆ๋Š”๋ฐ Int๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ฑฐ๋‚˜ ๊ตฌ์กฐ์ฒด์—์„œ ํ•„๋“œ๋ฅผ ๋ˆ„๋ฝํ•˜๋Š” ๋“ฑ โ€” ๋„ค์ดํ‹ฐ๋ธŒ ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ๋นŒ๋“œ๋ฅผ ๊ฑฐ๋ถ€ํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ํƒ€์ž… ์—๋Ÿฌ๊ฐ€ ๋Ÿฐํƒ€์ž„ ํฌ๋ž˜์‹œ์—์„œ ๋นŒ๋“œ ์‹œ์ ์˜ ์‹คํŒจ๋กœ ์ด๋™ํ•ฉ๋‹ˆ๋‹ค.

Strict TypeScript API๋ž€ ๋ฌด์—‡์ด๋ฉฐ ์™œ ์ค‘์š”ํ•ฉ๋‹ˆ๊นŒ?

React Native 0.80์—์„œ ๋„์ž…๋œ Strict TypeScript API๋Š” ์ˆ˜๋™์œผ๋กœ ์ž‘์„ฑ๋œ .d.ts ํŒŒ์ผ ๋Œ€์‹  React Native์˜ ์†Œ์Šค ์ฝ”๋“œ์—์„œ ์ง์ ‘ ํƒ€์ž…์„ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. ์ž„ํฌํŠธ๋ฅผ ๋ฃจํŠธ react-native ํŒจํ‚ค์ง€๋กœ ์ œํ•œํ•˜๊ณ  ๋”ฅ ์ž„ํฌํŠธ๋ฅผ ์ง€์› ์ค‘๋‹จํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ์•ˆ์ •์ ์ธ ๊ณต๊ฐœ API ํ‘œ๋ฉด์ด ์ •์˜๋˜๋ฉฐ, ์‚ฌ์šฉ์ž๊ฐ€ strict ํƒ€์ž…๋งŒ ์‚ฌ์šฉํ•˜๋Š” ํ•œ ๋‚ด๋ถ€ ๋ฆฌํŒฉํ† ๋ง์œผ๋กœ ์ธํ•ด ์‚ฌ์šฉ์ž ์ฝ”๋“œ๊ฐ€ ๊นจ์ง€์ง€ ์•Š์Šต๋‹ˆ๋‹ค. tsconfig.json์—์„œ "types": ["react-native/types/strict"]๋ฅผ ์„ค์ •ํ•˜์—ฌ ํ™œ์„ฑํ™”ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ค‘์ฒฉ๋œ ๋„ค๋น„๊ฒŒ์ดํ„ฐ ๊ฐ„์— React Navigation ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์–ด๋–ป๊ฒŒ ํƒ€์ž… ์ง€์ •ํ•ฉ๋‹ˆ๊นŒ?

๋„ค๋น„๊ฒŒ์ดํ„ฐ๋ณ„๋กœ ParamList ํƒ€์ž…์„ ์ •์˜ํ•˜๊ณ  NavigatorScreenParams๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์กฐํ•ฉํ•ฉ๋‹ˆ๋‹ค. ์Šคํƒ ๋‚ด์— ์ค‘์ฒฉ๋œ ํƒญ ๋„ค๋น„๊ฒŒ์ดํ„ฐ์˜ ๊ฒฝ์šฐ, ์Šคํƒ์˜ ํŒŒ๋ผ๋ฏธํ„ฐ ๋ฆฌ์ŠคํŠธ๊ฐ€ ํƒญ์˜ ํŒŒ๋ผ๋ฏธํ„ฐ ๋ฆฌ์ŠคํŠธ๋ฅผ ์ฐธ์กฐํ•ฉ๋‹ˆ๋‹ค: type RootStack = { Main: NavigatorScreenParams<TabParamList>; Modal: { id: string } }. ๋ชจ๋“  navigate() ํ˜ธ์ถœ์ด ์ „์ฒด ์ค‘์ฒฉ ๊ณ„์ธต ๊ตฌ์กฐ๋ฅผ ํ†ตํ•ด ํƒ€์ž… ์ฒดํฌ๋˜์–ด ์ž˜๋ชป๋œ ํ™”๋ฉด ์ด๋ฆ„์ด๋‚˜ ๋ˆ„๋ฝ๋œ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์ปดํŒŒ์ผ ์‹œ์ ์— ๊ฐ์ง€ํ•ฉ๋‹ˆ๋‹ค.

ํŒ๋ณ„ ์œ ๋‹ˆ์˜จ์€ React Native ์ƒํƒœ ๊ด€๋ฆฌ์—์„œ ์–ด๋–ค ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•ฉ๋‹ˆ๊นŒ?

ํŒ๋ณ„ ์œ ๋‹ˆ์˜จ์€ ์ƒํ˜ธ ๋ฐฐํƒ€์ ์ธ ์ƒํƒœ(loading, error, loaded)๋ฅผ status ํ•„๋“œ๋ฅผ ํ‚ค๋กœ ํ•˜๋Š” ์œ ๋‹ˆ์˜จ ํƒ€์ž…์˜ ๋ณ„๋„ ๋ถ„๊ธฐ๋กœ ๋ชจ๋ธ๋งํ•ฉ๋‹ˆ๋‹ค. TypeScript๋Š” switch ๋ฌธ์˜ ๊ฐ ๋ถ„๊ธฐ์—์„œ ํƒ€์ž…์„ ์ž๋™์œผ๋กœ ์ขํ˜€์ฃผ๋ฏ€๋กœ, state.data์— ๋Œ€ํ•œ ์ ‘๊ทผ์€ state.status === 'loaded'์ธ ๊ฒฝ์šฐ์—๋งŒ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ๋กœ๋”ฉ ์ธ๋””์ผ€์ดํ„ฐ๊ฐ€ ์—๋Ÿฌ ๋ฐ์ดํ„ฐ์™€ ๋™์‹œ์— ํ‘œ์‹œ๋˜๋Š” ๋ฒ„๊ทธ๋ฅผ ๋ฐฉ์ง€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์„ ํƒ์  ํ•„๋“œ์™€ boolean ํ”Œ๋ž˜๊ทธ๋กœ๋Š” ์ด ๋ฒ”์ฃผ์˜ ๋ฒ„๊ทธ๋ฅผ ๋ฐฉ์ง€ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

TurboModules์™€ ๊ธฐ์กด Native Modules ์‹œ์Šคํ…œ์˜ ์ฐจ์ด์ ์„ ์„ค๋ช…ํ•ด ์ฃผ์‹ญ์‹œ์˜ค.

Native Modules๋Š” ๋น„๋™๊ธฐ ๋ธŒ๋ฆฌ์ง€๋ฅผ ํ†ตํ•ด ํ†ต์‹ ํ•˜๋ฉฐ ๋ชจ๋“  ๋ฐ์ดํ„ฐ๋ฅผ JSON์œผ๋กœ ์ง๋ ฌํ™”ํ–ˆ์Šต๋‹ˆ๋‹ค. TurboModules๋Š” JSI(JavaScript Interface)๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋™๊ธฐ์ ์ด๊ณ  ์ง์ ‘์ ์ธ C++ ํ˜ธ์ถœ์„ ์ˆ˜ํ–‰ํ•˜๋ฉฐ ์ง๋ ฌํ™” ์˜ค๋ฒ„ํ—ค๋“œ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ ์ง€์—ฐ ๋กœ๋”ฉ(์•ฑ ์‹œ์ž‘ ์‹œ๊ฐ€ ์•„๋‹Œ ์ฒซ ์‚ฌ์šฉ ์‹œ ๋กœ๋“œ)์„ ํ†ตํ•ด ์ฝœ๋“œ ์Šคํƒ€ํŠธ ์‹œ๊ฐ„์„ ์ค„์ด๊ณ , Codegen์„ ์‚ฌ์šฉํ•˜์—ฌ TypeScript ์‚ฌ์–‘์—์„œ ํƒ€์ž… ์•ˆ์ „ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. ๊ธฐ์กด ์‹œ์Šคํ…œ์€ ReadableMap / NSDictionary ํŒŒ์‹ฑ์— ์˜ํ•œ ๋Ÿฐํƒ€์ž„ ํƒ€์ž… ๋ณ€ํ™˜์— ์˜์กดํ–ˆ์ง€๋งŒ, TurboModules๋Š” ์ปดํŒŒ์ผ ์‹œ์ ์— ํƒ€์ž…์„ ๊ฐ•์ œํ•ฉ๋‹ˆ๋‹ค.

React Native ๋ฉด์ ‘ ์งˆ๋ฌธ์—์„œ๋Š” JSI, Fabric, ๋ธŒ๋ฆฌ์ง€๋ฆฌ์Šค ์•„ํ‚คํ…์ฒ˜์— ๋Œ€ํ•ด ๋” ์ž์„ธํžˆ ๋‹ค๋ฃจ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

์—ฐ์Šต์„ ์‹œ์ž‘ํ•˜์„ธ์š”!

๋ฉด์ ‘ ์‹œ๋ฎฌ๋ ˆ์ดํ„ฐ์™€ ๊ธฐ์ˆ  ํ…Œ์ŠคํŠธ๋กœ ์ง€์‹์„ ํ…Œ์ŠคํŠธํ•˜์„ธ์š”.

๊ฒฐ๋ก 

  • Strict TypeScript API(0.80 ์ดํ›„)๋Š” ์•ˆ์ •์ ์ธ ๊ณต๊ฐœ ํ‘œ๋ฉด์œผ๋กœ ์ž„ํฌํŠธ๋ฅผ ์ œํ•œํ•˜์—ฌ ๋‚ด๋ถ€ ๋ณ€๊ฒฝ์œผ๋กœ ์ธํ•œ ํŒŒ์†์„ ๋ฐฉ์ง€ํ•ฉ๋‹ˆ๋‹ค โ€” ๋ชจ๋“  ์ƒˆ ํ”„๋กœ์ ํŠธ์—์„œ ํ™œ์„ฑํ™”ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค
  • Codegen์€ TypeScript ์‚ฌ์–‘ ํŒŒ์ผ์—์„œ ๋„ค์ดํ‹ฐ๋ธŒ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ƒ์„ฑํ•˜์—ฌ JS-๋„ค์ดํ‹ฐ๋ธŒ ๊ฒฝ๊ณ„์˜ ํƒ€์ž… ์—๋Ÿฌ๋ฅผ ๋Ÿฐํƒ€์ž„ ํฌ๋ž˜์‹œ์—์„œ ๋นŒ๋“œ ์‹œ์  ์‹คํŒจ๋กœ ์ „ํ™˜ํ•ฉ๋‹ˆ๋‹ค
  • RootStackParamList์™€ NativeStackScreenProps๋ฅผ ์‚ฌ์šฉํ•œ ํƒ€์ž… ์•ˆ์ „ ๋‚ด๋น„๊ฒŒ์ด์…˜ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ์ž˜๋ชป๋œ ํ™”๋ฉด ์ด๋ฆ„๊ณผ ๋ˆ„๋ฝ๋œ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์•ฑ ์‹คํ–‰ ์ „์— ๊ฐ์ง€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค
  • ํŒ๋ณ„ ์œ ๋‹ˆ์˜จ์€ ํ™”๋ฉด ์ƒํƒœ๋ฅผ ์ƒํ˜ธ ๋ฐฐํƒ€์ ์ธ ๋ถ„๊ธฐ๋กœ ๋ชจ๋ธ๋งํ•˜์—ฌ ๋ถˆ๊ฐ€๋Šฅํ•œ ์ƒํƒœ๋ฅผ ํƒ€์ž… ์ˆ˜์ค€์—์„œ ํ‘œํ˜„ ๋ถˆ๊ฐ€๋Šฅํ•˜๊ฒŒ ๋งŒ๋“ญ๋‹ˆ๋‹ค
  • ํƒ€์ž… ์‚ฌ์–‘์„ ๊ฐ–์ถ˜ TurboModules๋Š” ๊ธฐ์กด ReadableMap / NSDictionary ํŒŒ์‹ฑ์„ ๋Œ€์ฒดํ•˜์—ฌ JavaScript์—์„œ C++, ํ”Œ๋žซํผ ๋„ค์ดํ‹ฐ๋ธŒ ์ฝ”๋“œ๊นŒ์ง€ ์™„์ „ํ•œ ํƒ€์ž… ์•ˆ์ „์„ฑ์„ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค
  • TanStack Query๋ฅผ ์‚ฌ์šฉํ•œ ์ œ๋„ค๋ฆญ API ํ›…์€ ์—”๋“œํฌ์ธํŠธ์—์„œ ์ปดํฌ๋„ŒํŠธ๊นŒ์ง€ ์ˆ˜๋™ ์บ์ŠคํŒ… ์—†์ด ํƒ€์ž… ์ถ”๋ก ์„ ์œ ์ง€ํ•ฉ๋‹ˆ๋‹ค

์—ฐ์Šต์„ ์‹œ์ž‘ํ•˜์„ธ์š”!

๋ฉด์ ‘ ์‹œ๋ฎฌ๋ ˆ์ดํ„ฐ์™€ ๊ธฐ์ˆ  ํ…Œ์ŠคํŠธ๋กœ ์ง€์‹์„ ํ…Œ์ŠคํŠธํ•˜์„ธ์š”.

ํƒœ๊ทธ

#react-native
#typescript
#mobile-development
#new-architecture
#turbomodules

๊ณต์œ 

๊ด€๋ จ ๊ธฐ์‚ฌ

React Native 0.85 ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ: ์• ๋‹ˆ๋ฉ”์ด์…˜ ๋ฐฑ์—”๋“œ์™€ TypeScript API

React Native 0.85 (2026): ์ƒˆ๋กœ์šด ์• ๋‹ˆ๋ฉ”์ด์…˜ ๋ฐฑ์—”๋“œ, ์—„๊ฒฉํ•œ TypeScript API ๋ฐ ๋ฉด์ ‘ ์งˆ๋ฌธ

React Native 0.85์˜ ๊ณต์œ  ์• ๋‹ˆ๋ฉ”์ด์…˜ ๋ฐฑ์—”๋“œ, ํฌ์ŠคํŠธ ๋ธŒ๋ฆฌ์ง€ ์•„ํ‚คํ…์ฒ˜, Metro TLS์— ๋Œ€ํ•ด ์ฝ”๋“œ ์˜ˆ์ œ์™€ ๋ฉด์ ‘ ์งˆ๋ฌธ์„ ํ†ตํ•ด ์‹ฌ์ธต ๋ถ„์„ํ•ฉ๋‹ˆ๋‹ค.

React Native ์ƒˆ๋กœ์šด ์•„ํ‚คํ…์ฒ˜: Hermes V1, Fabric, TurboModules, ๋ธŒ๋ฆฟ์ง€๋ฆฌ์Šค ๋ชจ๋“œ ๊ธฐ์ˆ  ํ•ด์„ค

2026๋…„ React Native ์ƒˆ๋กœ์šด ์•„ํ‚คํ…์ฒ˜: Hermes V1, ๋ธŒ๋ฆฟ์ง€๋ฆฌ์Šค ๋ชจ๋“œ์™€ ๋ฉด์ ‘ ์งˆ๋ฌธ

React Native ์ƒˆ๋กœ์šด ์•„ํ‚คํ…์ฒ˜ ์‹ฌ์ธต ๋ถ„์„. Hermes V1 ์—”์ง„, ๋ธŒ๋ฆฟ์ง€๋ฆฌ์Šค ๋ชจ๋“œ, TurboModules, Fabric ๋ Œ๋”๋Ÿฌ์˜ ๊ธฐ์ˆ ์  ์„ธ๋ถ€์‚ฌํ•ญ, ์„ฑ๋Šฅ ๋ฒค์น˜๋งˆํฌ, ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ๊ฐ€์ด๋“œ, ๊ธฐ์ˆ  ๋ฉด์ ‘ Q&A๋ฅผ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค.

React Native ๋ชจ๋ฐ”์ผ ์•ฑ์„ ์œ„ํ•œ Expo Router ํŒŒ์ผ ๊ธฐ๋ฐ˜ ๋‚ด๋น„๊ฒŒ์ด์…˜ ์‹œ์Šคํ…œ

Expo Router๋กœ ๋ฐฐ์šฐ๋Š” React Native ํŒŒ์ผ ๊ธฐ๋ฐ˜ ๋‚ด๋น„๊ฒŒ์ด์…˜ ์™„๋ฒฝ ๊ฐ€์ด๋“œ

Expo Router๋ฅผ ํ™œ์šฉํ•œ React Native ํŒŒ์ผ ๊ธฐ๋ฐ˜ ๋ผ์šฐํŒ…์„ ์ฒด๊ณ„์ ์œผ๋กœ ๋‹ค๋ฃน๋‹ˆ๋‹ค. ๋ ˆ์ด์•„์›ƒ, ๋™์  ๋ผ์šฐํŠธ, ํƒ€์ž… ์•ˆ์ „ ๋‚ด๋น„๊ฒŒ์ด์…˜, ํƒญ, ๋ชจ๋‹ฌ, ๋ฏธ๋“ค์›จ์–ด ๋“ฑ 2026๋…„ ์ตœ์‹  ํŒจํ„ด์„ ์ข…ํ•ฉ์ ์œผ๋กœ ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค.