This file is read automatically by Claude Code and other AI coding assistants when working in this repository. Keep it up to date as the project evolves.
react-native-typescript-boilerplate is a production-ready React Native starter built with TypeScript. It ships with navigation, theming, localization, HTTP hooks, animations, and a provider-agnostic AI service layer (OpenAI, Anthropic Claude, Google Gemini) β all wired up and ready to extend.
- React Native: 0.84.1 Β· React: 19.x Β· TypeScript: 5.x (strict)
- Navigation: react-navigation v7 (Stack + Bottom Tabs)
- Animations: react-native-reanimated v4 + react-native-gesture-handler v2
- HTTP: axios + axios-hooks
- i18n: i18next + react-i18next
- Icons: react-native-vector-icons + react-native-dynamic-vector-icons
src/
βββ assets/ # Fonts (Montserrat 18 weights) and splash image
βββ hooks/ # Custom React hooks (useAIChat, useAICompletion)
βββ navigation/ # Stack + Bottom Tab navigator wiring
βββ screens/ # One folder per screen, co-located styles
β βββ ai-chat/ # AI Chat screen (demo for AI service layer)
β βββ detail/
β βββ home/
β βββ notification/
β βββ search/
β βββ settings/
βββ services/
β βββ ai/ # Provider-agnostic AI service layer
β β βββ providers/ # openai.ts Β· anthropic.ts Β· gemini.ts
β β βββ AIService.ts
β β βββ index.ts
β β βββ types.ts
β βββ event-emitter/ # Shared EventEmitter singleton
β βββ models/ # Shared TypeScript interfaces for screens
βββ shared/
β βββ components/ # Reusable RN* components + barrel index.ts
β βββ constants/ # SCREENS enum
β βββ localization/ # i18next setup (en + tr-TR)
β βββ theme/ # palette, LightTheme, DarkTheme, fonts, font-size
βββ utils/ # capitalizeFirstLetter, generateRandomNumber
All aliases are defined in both babel.config.js (Metro) and tsconfig.json (TypeScript). Always prefer aliases over relative paths.
| Alias | Resolves to |
|---|---|
@shared-components |
src/shared/components |
@shared-constants |
src/shared/constants |
@services/* |
src/services/* |
@screens/* |
src/screens/* |
@hooks |
src/hooks/index |
@models |
src/services/models |
@theme/* |
src/shared/theme/* |
@fonts |
src/shared/theme/fonts |
@font-size |
src/shared/theme/font-size |
@colors |
src/shared/theme/colors |
@utils |
src/utils |
@assets |
src/assets |
@event-emitter |
src/services/event-emitter |
@api |
src/services/api/index (stub β create if needed) |
@local-storage |
src/services/local-storage (stub β create if needed) |
After adding a new alias, run
npm run start:freshto reset Metro's cache.
Located in src/services/ai/. The layer is provider-agnostic β the same API works for OpenAI, Anthropic, and Gemini. Model names are never hardcoded; the developer passes whatever model string their API key supports.
interface AIConfig {
provider: "openai" | "anthropic" | "gemini";
apiKey: string;
model?: string; // pass any model string β no defaults enforced
temperature?: number; // default 0.7 in providers
maxTokens?: number; // default 1024 in providers
systemPrompt?: string;
baseURL?: string; // override for proxies or local LLMs
}
interface AIMessage {
id: string;
role: "user" | "assistant" | "system";
content: string;
timestamp: number;
}// Full response (awaits complete reply)
sendAIMessage(messages: AIMessage[], config: AIConfig): Promise<AIChatResponse>
// Streaming (tokens arrive via callbacks)
streamAIMessage(messages: AIMessage[], config: AIConfig, callbacks: AIStreamCallbacks): Promise<void>
// Helpers
buildUserMessage(content: string): AIMessage
buildSystemMessage(content: string): AIMessage// Multi-turn conversation with history management
const { messages, isLoading, isStreaming, error, sendMessage, streamMessage, clearMessages, setSystemPrompt } =
useAIChat({ config, initialMessages?, onResponse?, onError? });
// Single-shot completion
const { complete, result, isLoading, error, reset } =
useAICompletion({ config, systemPrompt? });- Create
src/services/ai/providers/<name>.tsimplementingIAIProvider - Add a
case "<name>":in thecreateProvider()switch inAIService.ts - Add
"<name>"to theAIProviderunion type intypes.ts - Add an entry to
AI_PROVIDER_LABELSandAI_BASE_URLSintypes.ts
- React components:
PascalCase.tsx+PascalCase.style.tsin the same directory - Shared components prefix:
RN(e.g.RNButton,RNAIMessage) - Non-component TS files:
camelCase.ts
- Always call
const styles = useMemo(() => createStyles(theme), [theme])inside the component createStylesreceives the fullExtendedThemeobject and returns aStyleSheet- Never hardcode color values β always use
colors.*fromuseTheme()
const theme = useTheme(); // returns ExtendedTheme (see global.d.ts)
const { colors } = theme;
// Available: colors.primary, colors.secondary, colors.text, colors.placeholder,
// colors.background, colors.card, colors.borderColor, colors.danger,
// colors.white, colors.black, colors.shadow, ...full palette- Use
RNBounceable(from@freakycoder/react-native-bounceable) for all touchable elements - Use
TextWrapper(@shared-components/text-wrapper/TextWrapper) for all text β never bare<Text> - Use
SafeAreaViewfromreact-native-safe-area-context(not fromreact-native)
- Props interfaces use the
Iprefix:IRNButtonProps,IRNAIMessageProps - Use
export type { Foo }for type-only re-exports - The config has
noUnusedLocalsandnoUnusedParametersβ every declared variable must be used - Exhaustive switches: add
const x: never = valin thedefaultcase
- External packages
- Path alias imports (
@services/...,@shared-components/..., etc.) - Relative imports (only when no alias covers it)
Screen name strings live in SCREENS (src/shared/constants/index.ts). To add a new screen:
- Add the key to
SCREENS - Import the screen component in
src/navigation/index.tsx - Add it as
<Tab.Screen>or<Stack.Screen> - Add its tab icon case in
renderTabIconif it's a tab
npm start # Start Metro bundler
npm run start:fresh # Start Metro with cache reset (required after adding aliases)
npm run ios # Run on iOS simulator
npm run android # Run on Android emulator
npm run lint # ESLint
npm test # Jest- Never hardcode hex color strings in component or style files
- Never use relative
../../imports where a path alias exists - Never import directly from provider files (
src/services/ai/providers/openai.ts) β use the@services/aibarrel - Never use bare
<Text>from react-native β useTextWrapper - Never use
TouchableOpacityβ useRNBounceable - Never add model name strings (e.g.
"gpt-4o") to the AI service layer β the developer provides them viaAIConfig.model - Never commit API keys β the AI chat screen stores them in component state only