$npx -y skills add margelo/react-native-skills --skill api-designDesign and review predictable public APIs for TypeScript, JavaScript, React, and React Native libraries. Use when shaping exported functions, classes, hooks, options objects, event and listener APIs, error behavior, naming, cross-platform abstractions, or JS-only packages. Pair w
| 1 | # API Design |
| 2 | |
| 3 | Use this skill before implementation or when reviewing a public API surface. Target explicit types, stable semantics, and no irrelevant internals in the public contract. |
| 4 | |
| 5 | If the library is a Nitro Module, use this skill for the public TypeScript and React API shape first, then use `build-nitro-modules` for Nitro-specific spec, native-state, and binding constraints. If the library is JS-only, React-only, or React Native JS-only, stay in this skill. |
| 6 | |
| 7 | ## Workflow |
| 8 | |
| 9 | 1. Sketch the user-facing TypeScript API before implementing internals. |
| 10 | 2. Write 2-3 realistic call-site examples, including error and cleanup paths. |
| 11 | 3. Check the surface against the rules below. |
| 12 | 4. Verify the exported TypeScript with the repo's typecheck/lint/docs tooling before treating the API as done. |
| 13 | 5. Implement only after the public shape is coherent and verified. |
| 14 | |
| 15 | ## API Freshness |
| 16 | |
| 17 | Before choosing public API shape, dependency APIs, platform capabilities, or implementation strategy, verify current official sources instead of relying on trained memory. Library, React, React Native, platform, and tooling APIs evolve quickly. |
| 18 | |
| 19 | - Prefer official docs, source repositories, release notes, changelogs, package READMEs, and current package metadata. |
| 20 | - Look for `llms.txt` or `llms-full.txt` on official docs sites when available, and use those as compact current context. |
| 21 | - Treat remembered API details as a starting hypothesis only. If current docs or source disagree, follow the current docs/source and mention the change when relevant. |
| 22 | - Avoid designing against stale blog posts, old snippets, or outdated trained assumptions when an official current source is available. |
| 23 | |
| 24 | ## API Shape Rules |
| 25 | |
| 26 | - Prefer a single source of truth. Do not split related state across booleans and dependent values when one typed value can express the state. Prefer `timeoutMs?: number` over `enableTimeout: boolean` plus `timeoutMs?: number`. |
| 27 | - Use option objects or named structs once a function has 3 or more parameters, parameters of the same primitive type, or values that are likely to grow. |
| 28 | - Keep APIs specific instead of accepting every possible input shape. A millisecond timeout should be a `number`, not `number | string | bigint | object | null`. |
| 29 | - Avoid giant "does everything" objects. Split by domain or lifecycle when responsibilities differ. |
| 30 | - Before simplifying or redesigning an API, inventory the workflows the feature is supposed to support. Do not silently drop a workflow, such as a live session API, because a one-shot path is easier to implement. Split workflows into separate APIs when needed. |
| 31 | - Prefer literal unions, discriminated unions, interfaces, and typed option groups when the valid states are known. In TypeScript libraries, prefer string literal unions over runtime `enum`s unless consumers need a runtime value. |
| 32 | - Avoid untyped dictionaries, boolean clusters, stringly typed commands, and loosely shaped events when the valid states are known. |
| 33 | - Do not model a binary option as an optional two-case string union such as `'enabled' | 'disabled'`. If omitted means "use the default" and provided means true/false, use an optional boolean and document the default. |
| 34 | - Do not represent multiple object states as one interface full of optional fields. Use a discriminated union, inheritance, or separate variant interfaces so impossible field combinations are unrepresentable. |
| 35 | - Keep related fields together on the variant where they are required. If `barcode` and `barcodeType` only make sense together, both should be nonoptional on `ScannedBarcode`, not optional on a generic `ScannedData`. |
| 36 | - If you create variant interfaces, use them in the actual public type. Do not define `RecognizedTextDataType` and `RecognizedBarcodeDataType` but keep `recognizedDataTypes: RecognizedDataType[]` where `RecognizedDataType` still contains every variant field as optional. |
| 37 | - Use `undefined` or optional fields for absence. Use `null` only when "explicit none" means something different from "not provided". |
| 38 | - Prefer discriminated unions for state machines, loading states, and result variants. |
| 39 | - Model user intent separately from resolved state when negotiation is involved. For example, an ordered array of constraint objects can express priorities, while a resolved config object reports what the platform actually selected. |
| 40 | - For complex negotiation, prefer ranked constraints or preference objects over exposing a combinatorial support matrix. Let callers describe intent, resolve the closest working configuration internally, and expose the resolved configuration through a return value, callback, or explicit resolver met |