关于 api-design
用于在实现前规划或审查公共 API 的技能,指导开发者采用明确类型、稳定语义和实际调用示例,并验证导出的 TypeScript。
主要功能
- 01优先勾勒面向使用者的 API
- 02编写实际调用示例
- 03检查类型与生命周期设计
- 04依据当前资料核实
- 05验证导出的 TypeScript
适用场景
- 01规划库的公共 API
- 02审查拟议的 API 表面
- 03设计 TypeScript 类型与生命周期
- 04实现前验证 API 变更
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ margelo/ react-native-skills --skill api-design安装后在 Claude Code 中输入/api-design确认已加载。
详细介绍
API 设计
在实现前或审查公共 API 接口时使用此技能。目标是提供明确的类型、稳定的语义,并确保公共契约不包含无关的内部细节。
如果该库是 Nitro Module,先使用此技能确定公共 TypeScript 和 React API 的形态,然后使用 build-nitro-modules 处理 Nitro 特有的规范、原生状态和绑定约束。如果该库仅使用 JS、仅使用 React,或仅使用 React Native JS,则只需使用此技能。
工作流
- 在实现内部细节前,先勾勒面向用户的 TypeScript API。
- 编写 2-3 个真实的调用示例,包括错误处理和清理流程。
- 根据以下规则检查 API 接口。
- 使用代码库的类型检查、lint 和文档工具验证导出的 TypeScript,然后再将 API 视为完成。
- 只有在公共 API 形态连贯且经过验证后,才开始实现。
API 时效性
在确定公共 API 形态、依赖项 API、平台能力或实现策略前,请查阅当前的官方资料,而不是依赖训练记忆。库、React、React Native、平台和工具 API 都在快速演进。
- 优先查阅官方文档、源代码仓库、发行说明、变更日志、软件包 README 和当前软件包元数据。
- 如果官方文档网站提供
llms.txt或llms-full.txt,请查找并使用它们作为精简的当前参考资料。 - 仅将记忆中的 API 细节视为初步假设。如果当前文档或源码与之不符,请以当前文档或源码为准,并在相关时说明变化。
- 如果有可用的官方当前资料,请避免依据过时的博客文章、旧代码片段或陈旧的训练假设来设计。
API 形态规则
- 优先采用单一事实来源。如果一个有类型的值就能表达状态,就不要把相关状态拆分成布尔值和依赖值。优先使用
timeoutMs?: number,而不是enableTimeout: boolean加上timeoutMs?: number。 - 函数有 3 个或更多参数、参数属于同一原始类型,或参数值很可能会增加时,请使用选项对象或具名结构体。
- 让 API 保持具体,不要接受所有可能的输入形态。以毫秒为单位的超时值应为
number,而不是number | string | bigint | object | null。 - 避免设计包揽一切的巨型对象。职责不同时,按领域或生命周期拆分。
- 简化或重新设计 API 前,先梳理该功能应支持的工作流。不要为了让单次调用路径更容易实现,就悄悄舍弃某个工作流,例如实时会话 API。必要时将不同工作流拆分为独立 API。
- 已知有效状态时,优先使用字面量联合、判别联合、接口和类型化选项组。在 TypeScript 库中,除非使用者需要运行时值,否则优先使用字符串字面量联合,而不是运行时
enum。 - 已知有效状态时,避免使用无类型字典、成组布尔值、字符串化命令和形状松散的事件。
- 不要将二元选项建模为可选的双值字符串联合,例如
'enabled' | 'disabled'。如果省略表示“使用默认值”,而提供时表示 true 或 false,请使用可选布尔值并说明默认值。 - 不要用一个包含一堆可选字段的接口来表示多个对象状态。使用判别联合、继承或独立的变体接口,使不可能的字段组合无法表示。
- 将相关字段放在它们必需的变体中。如果
barcode和barcodeType只有同时存在才有意义,就应在ScannedBarcode中将它们都设为必填,而不是在通用的ScannedData中设为可选。 - 如果创建了变体接口,就要在实际公共类型中使用它们。不要定义
RecognizedTextDataType和RecognizedBarcodeDataType,却仍使用recognizedDataTypes: RecognizedDataType[],而RecognizedDataType中依旧把所有变体字段设为可选。 - 缺失值使用
undefined或可选字段。仅当“明确为空”与“未提供”的含义不同时,才使用null。 - 对状态机、加载状态和结果变体,优先使用判别联合。
- 涉及协商时,应将用户意图与最终解析出的状态分开建模。例如,有序的约束对象数组可以表达优先级,而解析后的配置对象则报告平台实际选择的内容。
- 对于复杂协商,优先使用有序约束或偏好对象,而不是暴露组合式支持矩阵。让调用方描述意图,在内部解析最接近且可行的配置,并通过返回值、回调或显式解析器方法暴露解析后的配置。
- 使用
as const satisfies Record<string, Type>对象暴露常用预设。接受的类型应保持结构化,以便用户提供自己的值。 - 不要暴露调用方已知的环境事实,例如仅重复
Platform.OS的platform字段;除非 API 可能返回由不同于当前运行时的平台生成的数据。 - 不要将当前平台支持矩阵固化到类型形状中。优先使用
availableTextTypes: []或supportedFormats: []之类的运行时能力字段,而不是平台专属类型或静态排除项。这样,新的原生能力可用时,无需重新设计 JS API。 - 优先使用统一的选项对象。避免使用
ios/android选项包和平台前缀方法,除非相关概念确实只适用于特定平台,无法描述为跨平台能力或空操作。 - 将配置字段分类为要求或偏好。无法满足要求时应抛出错误。如果功能仍能完成核心任务,则应尽力满足偏好,例如质量、引导 UI、高帧率跟踪、自动缩放或更大的扫描区域。说明尽力满足的字段,并在调用方需要了解实际应用内容时暴露能力或解析后的配置。
- 当能力具有不同的选项、结果或未来发展方向时,按稳定的语义能力拆分。例如,即使当前某个原生 API 同时实现了条码扫描和文本扫描,它们也可能适合使用独立的
BarcodeScanner和TextScannerAPI。缺少文本扫描能力的平台应让createTextScanner()失败,或报告isTextScannerAvailable: false,而不是迫使条码扫描所用的通用扫描器将文本专属字段设为可空。 - 运行时可用性应描述某项稳定能力当前是否存在,而不是永久将 API 形状限制为当前平台矩阵。如果 Android 以后支持文本扫描,现有的
TextScanner能力应直接变为可用,而无需更改条码 API 或扩大结果类型中的可空范围。 - 能力发现应与对象契约分开。使用能力字段判断能否创建某个工作流,或哪些可选偏好可能适用。工厂返回特定会话或资源对象后,其基本方法应由对象的创建过程保证;否则,应返回更窄的类型或在创建时失败,而不是让调用方在每次调用常规方法前检查
can*。 - 拆分工作流应减少运行时能力检查。不要仅为了弥补对象过于庞大而保留宽泛的能力标记。例如,可将单次扫描器和应用拥有的实时扫描器设计为独立 API;如果实时扫描器的实现保证支持缩放、拍照或区域控制,这些功能就可以成为实时扫描器契约的一部分,而不是从单次扫描后端继承来的可空属性加
can*检查。 - 在 API 对象图中编码生命周期转换。如果命令只有在
configure、connect、start或其他生命周期转换后才有效,就应将这些命令放在该转换所返回的句柄上,而不是放在需要检查“可能处于活动状态”的父对象上。例如,session.configure(device, outputs)可以返回一个负责setZoom(...)和focusTo(...)的Controller;Session则负责图配置和启动、停止。 - 避免过时状态 API。如果重新配置会更改命令所针对的原生资源,就应返回新句柄,并使旧句柄失效或将其释放。调用方不应意外地在不知道适用配置设备或输出的父对象上调用命令。
- 使用回调或返回的解析后对象表示协商后的事实。如果输出、控制器或会话配置只有在连接后才有意义,请提供
onConfigured、返回控制器/配置对象或显式的resolve...(...)方法,而不是迫使调用方轮询可空属性。 - 对于由 Nitro 支持的命令式 API,默认将公共 HybridObject 视为 API。不要添加 JS 封装层来预解析输入、转换枚举/字符串形状、将一种公共格式规范化为另一种格式,或以其他方式使 JS 调用不同于生成的 Nitro 规范的 API。应直接在 Nitro 规范和原生实现中定义预期的公共形状。
- 当“全部”是有意义的请求值时,应明确建模,而不是将
undefined用作隐藏命令。例如,当实现受益于具体值时,优先使用targetFormats: 'all' | BarcodeFormat[]或TargetBarcodeFormat = BarcodeFormat | 'all'。 - 不要返回半初始化对象,让调用方必须先单独调用
prepare()、initialize()或load()才能正常使用。如果必须进行设置,就让工厂方法为异步,并在返回可用对象后完成解析。生命周期方法应用于start()/stop()之类真正可重复的转换,而不是构造就绪状态。 - 对于较大的库,应提供一个精简的公共根对象或工厂,用于创建有状态的领域对象。通过工厂方法处理对象构造、异步设置、I/O 和验证,而不是迫使调用方使用静态函数或尚未就绪的实例。
- 仅在正常的领域数据缺失时返回
undefined,并准确说明其出现条件。不要用可选返回值作为未说明的错误处理路径;操作失败时应抛出错误或拒绝 Promise。 - 决定返回的数据是普通值还是资源。对于字段成本低且语义完整的小型不可变数据,使用普通结构体/接口。如果值拥有原生状态、需要延迟执行高成本访问、可能增加行为,或将来应公开方法,则使用类/对象/资源。
- 首先依据语义选择数据表示,再考虑性能。解码后的文本内容使用
string。对于原始二进制、不可解释字节、媒体或将零拷贝访问作为契约一部分的大型数据,使用ArrayBuffer或面向字节的对象。
变体示例
当一个对象可能处于几种不同状态时,避免使用可空字段簇:
interface ScannedData {
position: Point
text?: string
barcode?: string
barcodeType?: BarcodeType
face?: Rect
}
优先使用基类型加上包含非可选状态专属字段的变体:
interface ScannedData {
position: Point
}
interface ScannedText extends ScannedData {
text: string
}
interface ScannedBarcode extends ScannedData {
barcode: string
barcodeType: BarcodeType
}
interface ScannedFace extends ScannedData {
face: Rect
}
type ScannedResult = ScannedText | ScannedBarcode | ScannedFace
公共 API 组织
- 将公共接口拆分到职责明确的文件或模块中,并从清晰的包入口重新导出。不要创建包含某项功能的主要对象以及所有枚举、选项、结果、事件和辅助类型的兜底文件。
- 默认每个文件导出一个公共类型。只有当多个导出类型构成一个紧密耦合的逻辑结构,且很少单独导入时,才将它们放在同一个文件中,例如
DynamicRange类型及其定义所需的精确字面量联合类型。 - 仅从
src/index.ts等包入口重新导出公共包类型。不要让功能、规范或类型文件重新导出同一文件夹中的无关类型。 - 在包入口使用直接重新导出语法,而不是先导入再重新导出。类型专用符号使用
export type { Foo } from './Foo',运行时值使用export { Foo } from './Foo'。 src/index.ts、index.ts、index.js和index.tsx等包入口只能用作导出汇总文件。不要在其中定义函数、类、钩子、组件、辅助常量、分支逻辑、副作用或实现逻辑。唯一允许的运行时声明是简单的一行包根声明,例如export const camera = NitroModules.createHybridObject<Camera>('Camera');其他内容都应放在职责明确的文件中,再从入口重新导出。- 如果类型可以按概念拆分,例如条码格式、扫描值、配置、能力和订阅,那么 600 行的类型/规范文件不可接受。
- 将共享字段和方法放在基接口或基类上。子类型只应添加该子类型特有的成员,不要在每个具体变体中重复
format、valueType、id或bounds等字段。 - 将辅助函数和转换放在最小且有意义的接收者上:如果转换只读取一个元素,就将它放在该元素上,即使返回的目标值数量为零、一个或多个。调用处使用常规的
map、flatMap、reduce或Set(...)来组合数组。 - 仅当集合本身具有领域语义时,才添加集合级辅助函数,例如跨元素验证、去重、顺序保证、缓存、性能优化所需的批处理、非空检查或错误聚合。不要仅为隐藏一次标准集合操作而添加集合辅助函数。
- 除非性能或实现策略会改变调用者使用 API 的方式,否则不要将其纳入公共接口。例如,API 可以公开明确的转换方法,但除非相关行为可直接观察到,否则名称和文档不应宣传“惰性”“轻量级”或“已规范化”等内部细节。
TypeScript 和 JavaScript 风格
- 绝不要将
void 0用作 undefined 值。请明确写出undefined。 - 绝不要在包/运行时代码中使用
??=、||=或&&=等逻辑赋值运算符。优先使用显式的if语句块或直接赋值,让调用处的变更和回退行为一目了然。
名称与成员
- 命令名称应包含动词和主体。为数值添加单位后缀。优先使用
getCurrentSystemTimestampMs(),而不是timestamp()。 - 布尔值的名称应体现其作用,而不只是类型。
- 对于反映观察到的状态、能力或已解析配置的布尔值,使用
is*、has*、can*或supports*等谓词名称。例如:isFlashEnabled、isFlashAvailable、hasFlash、supportsFlash。 - 对于用于控制未来行为的布尔选项,使用
enable*、allow*等命令或偏好名称,或使用特定领域的动词。例如:enableFlash、allowCellularAccess、preferHighAccuracy。 - 在 React 和 React Native 公共 API 中,将
use*名称保留给 hooks。在 React 上下文之外,仅当use*符合本地领域的自然表达且不会与 hook 混淆时,才可以使用。 - 当某项功能尚未启用时,避免对输入偏好使用
is*Enabled。enableGuidance?: boolean表示请求的设置;isGuidanceEnabled: boolean表示已解析的状态。 - 对于开销低的已观察状态或能力,使用属性。优先使用
readonly isAccelerometerAvailable: boolean,而不是accelerometerAvailable()。 - 对于副作用、开销较大的操作、分配、变更、异步边界或可能失败的操作,使用方法。
- 在名称中明确标示单位:
timeoutMs、byteSize、maxRetries、createdAt。 - 避免机械地为每个导出的类型添加包、模块或功能名称前缀。导入和包命名空间已提供上下文,必要时调用方可以为名称设置别名。仅当不带前缀的名称在包根导入位置存在歧义时才使用前缀;优先使用
CameraPermissionStatus、ScannedResultSource、Point或Rect等领域名称,而不是在每个类型上重复DataScanner。 - 对由调用方观察但不设置的公共状态,使用
readonly。仅当赋值本身就是预期命令时,才使用可变属性。 - 可写属性必须开销低、同步执行且不太可能失败。如果设置值需要原生协商、权限、I/O、分配、可能失败的验证,或跨线程/进程切换,则应公开明确的异步方法,例如
setZoomFactor(zoomFactor): Promise<void>。 - 对于公共字符串字面量联合类型,优先使用小写 kebab-case 值,例如
manual-input,而不是 camelCase 值,例如manualInput。
异步操作、事件与 React
- 当结果能立即获得、具有确定性、成本低且在本地完成时,使用同步 API。不要仅仅因为实现是原生的,就把简单的值构造、缓存的元数据或纯转换包装成异步操作。
- 一次性异步工作使用
Promise。对于重复事件,使用监听器 API、流或可观察存储。 - 权限、硬件/会话设置、I/O、采集/录制、平台异步 API、阻塞工作、原本就是异步的原生 API,或可能跨越线程或进程边界的工作,都使用
Promise。繁重或复杂的工作应交由自有的 worker/队列/调度器/运行时执行,而不是阻塞调用方。 - 除非底层平台 API 要求,否则不要使用主线程/UI 线程。主线程 API 在该线程上只应执行必要的 UI 工作,并将繁重的设置、转换、解析、I/O 和计算移至自有的后台上下文。
- 不要在任意层之间传递 Promise 的解析器状态。优先在异步边界返回 Promise,并使用
async/await、原生 Promise 辅助函数,或在确切的桥接点使用简单的完成回调。悬而未决的 Promise 和重复解析都是生命周期错误。 - 对有歧义的 API 进行基准测试。如果常规使用可能阻塞可见的 UI 工作、等待另一个线程/进程,或运行时间不可预测,就将方法设计为异步。
- 如果某项转换既有开销低的路径,也有可能开销很大的路径,应提供明确的同步和异步方法,例如
convertX()和convertXAsync(),而不是用一个含义模糊的方法隐藏阻塞工作。 - 将反复在内部切换线程/队列/运行时视为 API 设计异味。优先使用拥有自身执行上下文的对象,或使用显式异步生命周期方法,仅跨入该上下文一次。如果调用方需要另一个线程上的结果,应公开
Promise、监听器、流或返回有状态句柄,而不是用看似同步的方法或属性隐藏一连串线程切换。 - 不要用
setTimeout、休眠、人工延迟、额外的线程切换或重复调用同一方法来修复竞态、就绪状态或顺序错误。这些做法会掩盖有缺陷的生命周期契约。应修复状态机、公开明确的就绪/完成事件、返回已配置的句柄,或将操作正确地设计为异步。只有在网络、远程服务、OS 服务或硬件等外部因素导致结果不可确定时才适合重试;重试必须有次数上限、可取消且可安全重复。 - 使用带清理机制的显式监听器方法,而不是可写的回调属性:
addOnValueChangedListener(listener): ListenerSubscription,而非onValueChanged?: (...) => void。 - 在方法签名中内联简单的监听器回调参数。只有在用户会直接导入该类型、多个 API 共用同一函数契约,或回调除了监听器函数外还有明确的领域含义时,才导出具名回调类型。
- 注册监听器必须返回清理句柄。避免使用
addListener(...): number加removeListener(listenerId: number),因为由调用方管理 ID 容易泄漏、难以安全地进行类型检查,还会迫使实现使用隐藏的全局/静态监听器表。优先使用扁平的订阅对象,其中包含拥有原生或内部清理逻辑的幂等remove函数。 - 对于重复观察或事件,默认使用
addOn...Listener(callback): ListenerSubscription。这既支持多个彼此独立的使用方,也让每个调用方都能明确负责清理。若一个调用方可能意外替换另一个调用方的监听器,不要使用单个setOn...回调槽。 - 监听器清理应阻止后续事件发出,但不应承诺取消已经从快照开始分发的事件。不要让 API 或实现变得过于复杂,只为保证在分发期间被移除的回调不会收到当前事件。
- 只有在语义本就要求替换时,才使用
setOn...(callback | undefined)风格的 API:对象只有一个回调槽、回调更像配置而非事件订阅,或高性能原生处理流水线无法合理地支持多个监听器。应说明该 API 会替换之前的回调,并且传入undefined会将其移除。 - 不要只依靠
Callback或Listener后缀来说明所有权。add...与set...这两个动词以及返回类型,应清楚表明回调是可追加且由调用方负责的,还是单个可替换槽位。 - 对于一次性操作的进度,如果回调属于某次方法调用,例如采集或上传进度回调,应使用回调选项对象。
- 除非原生侧的内部记录本身就是该功能,否则不要将其暴露为事件契约。优先提供简单的观察结果,并在开销低且更清晰时让 JS 推导特定于应用的差异或状态。
- 在 React 或 React Native 库中,如果某个值需要驱动 UI,应在稳定的命令式 API 之上提供 hooks。使用合适的 React 原语,例如用
useEffect管理订阅,或用useSyncExternalStore管理外部状态。 - hooks 应作为命令式核心的适配层,而不是使用该库的唯一方式。
- 对于 React 组件,应包装命令式核心,而不是创建一套平行 API。组件可以负责设置、引用、手势和生命周期,而 hooks 则为高级用法提供相同的底层对象。
- 为订阅使用稳定的回调并进行确定性清理。当遗漏事件会造成可观察影响时,应在可能发出事件的生命周期副作用开始前订阅。
错误和平台差异
- 切勿静默吞掉用户可触发的错误。不要只是返回、记录日志或不执行任何操作。应抛出错误、拒绝 Promise,或通过专用错误监听器发出错误。
- 失败和错误事件应使用真正的 JavaScript
Error对象,而不是自定义的{ code, message }结构;除非 API 有意跨越无法保留原型的边界序列化错误。 - 不支持必需的功能或输入无效时,应抛出具体错误。指出缺失的功能、无效值、有效范围或平台限制。
- 如果某个平台忽略了其他平台支持的可选偏好设置,不要仅因此抛出错误。如果忽略该设置不会影响用户期望的结果,就应优雅降级,并通过功能能力或解析状态 API 显示该设置是否生效。
- 如果忽略某个选项会违背用户意图、安全要求、隐私要求或可见结果的正确性,就应抛出错误。例如,必需的闪光灯模式在没有闪光灯的硬件上应报错;尽力满足的画质提示则可以回退。
- 存在真正可行的替代方案时,应在错误消息中说明。
- 静态断言或致命错误只用于不可能发生的内部状态,不用于可由 JavaScript 用户代码触发的状态。
- 对于 React Native,应设计跨平台概念,而不是一对一照搬 iOS 和 Android API。除非低层访问本身就是功能,否则应避免暴露原生类名或框架细节。
- 对于 GPU、零拷贝、原生资源和硬件 API,应明确表达低层概念。如果通用的 Web 风格命名会掩盖所有权、复制、同步/异步行为、线程亲和性或释放方式,就不要强行采用这种命名。
避免变通 API
- 除非调用方确实需要据此进行判断,否则不要将临时补丁、平台缺陷、依赖项怪癖或过时的实现细节编码进公共 API 结构中。
- 优先修复根本原因、使用官方扩展点,或通过稳定的领域 API 隐藏兼容性代码。
- 如果变通方案无法避免,应尽可能将其限制在内部且保持范围狭窄。如果必须公开,应说明存在原因、跟踪的问题,以及何时可以移除。
TypeScript 外观层
- 避免为公共 Nitro HybridObjects 添加 JS/TS 外观层。如果调用方应使用命令式 Nitro API,就按照
.nitro.ts规范和原生实现的定义一对一导出;不要包装 API 来预解析参数、转换字符串/枚举、注入隐藏默认值,或改变错误/生命周期行为。 - 只有在有意提供更高层级的 API 时才使用 JS/TS 包装器,例如 React hooks、React 组件、便于使用的 UI 组合,或 Nitro HybridObject 属于与面向用户的心智模型不符的内部实现细节时。
- 如果 JS 外观层改变了失败行为、默认值、生命周期、所有权或可接受的值形式,就应将这些规则移入 Nitro 规范/原生实现,除非该外观层有意作为产品 API,且 HybridObject 属于内部实现。
- 示例应展示真实的设置、清理、功能不可用时的行为,以及无效输入。
文档约定
- 将导出的 TypeScript 视为产品文档。为用户导入的每个导出声明添加 JSDoc,包括接口、类型别名、字符串字面量联合类型、运行时枚举、类、HybridObject、选项对象、事件对象、钩子、组件和公共常量。
- 假设这些注释会通过 TypeDoc 或类似生成器生成 API 文档。应将其写成便于浏览的参考文档,而非仅供代码内阅读的注释。
- 每个 JSDoc
{@linkcode ...}或@see目标都必须能在其所在文件中解析。必要时,为仅在文档中引用的符号导入类型,或链接到当前作用域中已有的本地符号。不要因为tsc恰好能通过,就留下编辑器或文档工具中的波浪线。 - 不要仅为附加 JSDoc 而创建导出的回调别名。应内联简单的回调参数,并为接受它们的方法或参数编写文档。只有在回调类型有意作为公共 API 的一部分时,才导出并记录该类型。
- 对于类型无法表达的语义、生命周期、平台行为、默认值和性能开销,使用 JSDoc 说明。
- JSDoc 应面向用户。除非调用者必须了解原生类名、框架实现细节或当前平台限制才能正确使用 API,否则不要提及这些内容。
- 编写 JSDoc 时应解释领域含义,而不是说明该 API 使用 JavaScript。避免“已为 JavaScript 规范化”之类空洞的注释,优先使用“表示条形码的格式”或“表示扫描文本值的内容类型”等具体说明。
- 为每个公共属性编写文档,包括选项、能力、结果、事件和 HybridObject 上的属性。显而易见的字段可以简短说明,但默认值、单位、可用性、失败行为以及与相关选项的交互方式,都应在对应属性上说明。
- 每个类型级 JSDoc 都应通过
{@linkcode ...}或@see将该类型关联到实际相关的 API。链接到公开该类型的属性、方法、工厂或结果,例如表示 {@linkcode Barcode} 的格式。加上@see {@linkcode Barcode.format}。不要编造链接目标,也不要仅为满足此规则而添加填充式链接。 - 对于基础接口或抽象概念,应说明调用者如何接触到该值,并链接到包导出的具体变体。例如:
表示由 {@linkcode DataScanner} 扫描的值。具体值包括 {@linkcode ScannedTextValue} 和 {@linkcode ScannedBarcodeValue}。 - 使用
{@linkcode ...}或@see指向相关方法、配置对象和能力检查,而不是泛泛提醒用户不要假定当前操作系统或平台。 - 文档中的链接应足够丰富,便于用户在生成的 API 参考中浏览:工厂应链接到返回的对象,选项应链接到使用它们的方法,结果对象应链接到生成它们的方法,事件应链接到监听器注册方法,清理和释放文档应链接到创建资源的 API。
- 在能帮助说明行为时,使用
@default、@throws、@platform、@example、@see和@discussion。使用{@linkcode ...}链接相关 API。 - 明确说明资源的所有权和清理方式。如果返回的对象必须释放,应说明何时以及为何需要释放。
评论
支持 Markdown