expo/expo-api-docs
Write TSDoc comments for Expo SDK APIs following official conventions. MUST USE when introducing new user-facing TypeScript APIs in expo-* packages - document APIs correctly from the start, not as an afterthought. Also use when improving existing documentation. Covers @platform, @example, @deprecated, @default annotations, third-person declarative style, blockquote notes, and type export patterns for docs generation.
npx skills add https://github.com/expo/expo --skill expo-api-docs
Guidelines for writing TSDoc comments in Expo SDK packages. The docs generation system (GenerateDocsAPIData.ts + TypeDoc) extracts these comments to produce API reference documentation.
Document APIs as you write them, not as an afterthought. When implementing new features, write TSDoc comments alongside the code.
packages/expo-*width propertyUse third-person declarative ("Gets...", "Returns...", "Checks..."), not imperative ("Get...", "Return...").
/**
* Gets the uptime since the last reboot of the device, in milliseconds.
* Android devices do not count time spent in deep sleep.
*
* @return A promise fulfilled with the milliseconds since last reboot.
*
* @example
* ```ts
* const uptime = await Device.getUptimeAsync();
* // 4371054
* ```
*
* @platform android
* @platform ios
*/
export async function getUptimeAsync(): Promise<number> {
Key points:
/**
* Sets the sensor update interval.
*
* @param intervalMs Desired interval in milliseconds between sensor updates.
* > Starting from Android 12 (API level 31), the system has a 200Hz limit for each sensor updates.
* >
* > If you need an update interval less than 5ms, add `android.permission.HIGH_SAMPLING_RATE_SENSORS`
* > to [**app.json** `permissions` field](/versions/latest/config/app/#permissions).
*/
setUpdateInterval(intervalMs: number): void {
Format: @param paramName Description starting with capital letter
Parameters can include:
Document each property individually:
export type GetImageOptions = {
/**
* The format of the clipboard image to be converted to.
*/
format: 'png' | 'jpeg';
/**
* Specify the quality of the returned image, between `0` and `1`.
* Applicable only when `format` is set to `jpeg`, ignored otherwise.
* @default 1
*/
jpegQuality?: number;
};
Teach something useful. Bad: "The width". Good: "The width of the captured photo, measured in pixels".
| Tag | Purpose | Example |
|-----|---------|---------|
| @param | Parameter description | @param options Configuration for the request |
| @return / @returns | Return value description | @return A promise fulfilled with the result |
| @default | Default value (no markdown, rendered as inline code) | @default 1 |
| @platform | Platform availability (android, ios, web, expo) | @platform ios 11+ |
| @example | Code example (placed at bottom of description) | See examples below |
| @deprecated | Deprecation notice (auto-formatted as warning) | @deprecated Use newMethod() instead |
| @experimental | Experimental API label | @experimental |
| @hidden / @internal / @private | Hide from generated docs | @hidden |
| @header | Group methods under custom headers | @header Scheduling |
| @needsAudit | Mark for security/API audit (comment, not tag) | // @needsAudit |
| @hideType | Hide generated Type callout for constants | @hideType |
Platform tag notes:
@platform when all platforms are supported — only add when limiting availability@platform tags for multiple platforms (one per line)@platform ios 11+android, ios, web, expo (Expo Go)Always wrap in triple backticks with language tag:
/**
* Checks device root/jailbreak status.
*
* @example
* ```ts
* const isRooted = await Device.isRootedExperimentalAsync();
* if (isRooted) {
* console.warn('Device may be compromised');
* }
* ```
*/
Use > blockquotes for important callouts:
/**
* > **Note:** This method requires the `CAMERA` permission.
*
* > **warning** This method is experimental and not completely reliable.
*/
Formats:
> Note: — informational> warning — caution (lowercase "warning")> on each line with blank > between paragraphs/**
* `true` if the app is running on a real device and `false` if running
* in a simulator or emulator. On web, this is always set to `true`.
*/
export const isDevice: boolean = ExpoDevice.isDevice;
Document the enum and individual values:
/**
* Type used to define what type of data is stored in the clipboard.
*/
export enum ContentType {
PLAIN_TEXT = 'plain-text',
HTML = 'html',
IMAGE = 'image',
/**
* @platform iOS
*/
URL = 'url',
}
Use "resolves to" in @returns tags, following MDN's convention:
@returns A promise that resolves to a CameraPhoto object.@returns A promise fulfilled with a CameraPhoto object.In inline prose, "resolves with" is acceptable (e.g. "The promise resolves with the parsed result").
Critical: Types must be exported from the entry point file for docs generation to pick them up.
Direct re-export from types file:
// index.ts or MainModule.ts
export {
type FileCreateOptions,
type DirectoryCreateOptions,
type FileHandle,
} from './Module.types';
Re-export after import:
// Haptics.ts
import { NotificationFeedbackType, ImpactFeedbackStyle } from './Haptics.types';
// ... function implementations ...
export { NotificationFeedbackType, ImpactFeedbackStyle };
The GenerateDocsAPIData script processes the entry point specified in its package mapping and extracts all publicly exported symbols.
When writing examples in documentation pages:
import * as FileSystem from 'expo-file-system';
const content = await FileSystem.readAsStringAsync(uri);
Always include:
ts, tsx, js, json, swift, kotlin)<SnackInline label="Basic file read" dependencies={['expo-file-system']}>
import * as FileSystem from 'expo-file-system';
export default function App() {
// ...
}
</SnackInline>
<Collapsible summary="Advanced usage with error handling">
try {
const result = await someAsyncOperation();
} catch (error) {
console.error('Operation failed:', error);
}
</Collapsible>
End documentation pages with:
<APISection packageName="expo-file-system" apiName="FileSystem" />
This auto-generates the API reference from TSDoc comments.
Do:
@platform tags for platform-specific APIs@example blocksDon't:
@link tag (not supported — use standard markdown links)@platform tags when all platforms are supportedTake expo/expo-api-docs from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.