@gj-kit/expo-workouts 레시피
각 코드 블록은 패키지 README에서 이미 타입 검사하는 public-contract 예제를 재사용합니다.
1. access를 요청하기 전에 native availability 확인하기
섹션 제목: “1. access를 요청하기 전에 native availability 확인하기”웹이나 Expo Go fallback이 아니라 development build에서 availability와 permission부터 시작합니다.
완료 상태: native Expo 앱에서 HealthKit 또는 Health Connect 사용 가능 여부를 확인하고 운동 권한을 요청합니다.
앱 소유 경계: config plugin을 추가하고 development build를 사용하세요. Expo Go와 웹은 native module을 호출할 수 없습니다.
import { getAvailability, requestAuthorization } from '@gj-kit/expo-workouts';
export async function requestWorkoutAccess() { const availability = await getAvailability(); if (availability.status === 'available') { await requestAuthorization({ read: ['workouts'] }); } return availability;}2. 운동 쓰기 결과를 안전하게 narrowing하기
섹션 제목: “2. 운동 쓰기 결과를 안전하게 narrowing하기”saved 상태에서만 native ID를 읽고 플랫폼이 쓸 수 없을 때는 그 사유를 보존합니다.
saveWorkout에서 production에 가서야 드러나는 실수는 둘입니다. route 누락과 잠긴 기기 분기 미처리 — 각각 TS2741과 TS2339로 컴파일 단계에서 걸립니다.
import { workouts } from '@gj-kit/expo-workouts';import type { WorkoutWrite } from '@gj-kit/expo-workouts/core';
export const write: WorkoutWrite = { id: 'a2f6c0b8-0d7e-4f31-9d1a-7c2b5e8f0a11', // your own idempotency key, not the platform's version: 3, // never Date.now(): a crash retry would mint a second workout kind: 'running', startMs: 1_754_000_000_000, endMs: 1_754_000_600_000, route: 'none', // delete this line -> TS2741; an Android upsert without it erases the stored route};
export async function save(): Promise<string | null> { const saved = await workouts.saveWorkout(write); // @ts-expect-error TS2339 — `nativeId` is absent on the `pendingUnlock` branch void saved.nativeId; if (saved.status === 'pendingUnlock') return null; // locked device: retry the same id + version return saved.nativeId; // narrowed past pendingUnlock, so it exists}전체 API reference에서 모든 export와 import path를 확인하세요.