☰
TypeDoc @readonly 标签详解:将可写成员标记为文档只读
2026/9/26 7:41:18 网站建设 项目流程
  • 开发工具
  • 文档

【免费下载链接】typedoc

Documentation generator for TypeScript projects.

项目地址:https://gitcode.com/gh_mirrors/ty/typedoc
点击查看免费下载

导读

@readonly是 TypeDoc 提供的一组修饰符标签(Modifier Tag)之一,它允许你在 TypeScript 类型系统认为某个成员“可写”的情况下,仍指示 TypeDoc 在生成文档时将其呈现为只读(non-writable)。本文结合 TypeDoc 仓库源码,完整讲解@readonly的语义、底层处理流程、渲染效果与测试用例,帮助你在 API 文档中精确表达“消费方不应修改”的设计意图。

@readonly标签语义

根据 site/tags/readonly.md 的官方说明:

The@readonlytag indicates that a reflection should be documented as non-writable, even if writable according to TypeScript.

即:@readonly的作用是覆盖 TypeScript 本身的可写性判断。无论 TypeScript 认为该成员是否有 setter、是否可赋值,只要注释中带有@readonly,TypeDoc 就会将其记录为只读并如此渲染。

该标签属于修饰符标签(Modifier Tag),与@private、@protected、@public、@abstract、@sealed等同属一类,完整清单见 tags.md。

官方示例:getter 与 setter 的处理

原文档给出的示例展示了一个经典场景——某个属性同时定义了 getter 与 setter,但从文档视角应视为只读:

export class Readable { /** @readonly */ get prop() { return 1; } /** Will be removed from the documentation due to the readonly tag */ set prop(_: number) { throw new Error("Not permitted"); } }

在这个例子中:

  • getterprop上的@readonly使整个属性在文档中被标记为只读;
  • setterprop的注释也说明它会因 readonly 标签而从文档中移除。

源码级解析:@readonly的完整处理链路

1. 修饰符识别与标志设置

@readonly的解析发生在转换器插件 CommentPlugin.ts 的applyModifiers中。当注释包含@readonly修饰符时(第 234–240 行):

if (comment.hasModifier("@readonly")) { const target = reflection.kindOf(ReflectionKind.GetSignature) ? reflection.parent! : reflection; target.setFlag(ReflectionFlag.Readonly); comment.removeModifier("@readonly"); }

关键逻辑在于:

  • 如果反射对象是GetSignature(getter 签名),则把Readonly标志设置到它的父级(即属性/访问器本身);
  • 否则直接设置到当前反射对象;
  • 处理完成后会从注释中移除@readonly修饰符,确保它不会以原始标签形式出现在渲染结果中。

ReflectionFlag.Readonly定义在 Reflection.ts 中,是一个位标志:

export enum ReflectionFlag { None = 0, // ... Readonly = 1 << 9, // ... }

同时它被列入relevantFlags(第 45–53 行),并对外暴露isReadonlygetter(第 124–125 行),供渲染模板查询:

get isReadonly() { return this.hasFlag(ReflectionFlag.Readonly); }

2. 解决阶段:隐藏 setter 并清理标志

在onBeginResolve(第 361–368 行)中,TypeDoc 会遍历项目中的反射,对**访问器(Accessor)**做特殊处理:

if (ref.kindOf(ReflectionKind.Accessor) && ref.flags.isReadonly) { const decl = ref as DeclarationReflection; if (decl.setSignature) { hidden.add(decl.setSignature); } // Clear flag set by @readonly since it shouldn't be rendered. ref.setFlag(ReflectionFlag.Readonly, false); }

这段代码揭示了两点实现细节:

  1. setter 被加入隐藏集合:凡是被@readonly标记的访问器,其setSignature会被隐藏,最终通过project.removeReflection从文档中移除——这正是原文档示例中 setter “被移除”的底层原因;
  2. 清除访问器本身的 Readonly 标志:注释明确指出该标志“不应被渲染”(shouldn't be rendered),因为只读性最终体现在签名渲染的关键字上,而不是访问器本身上。

3. 渲染阶段:readonly关键字的输出

只读标志最终会以 TypeScript 的readonly关键字形式出现在生成的文档签名中。在默认主题的索引签名渲染中可以看到:

  • templates/reflection.tsx(第 79–84 行):
{index.flags.isReadonly && ( <> <span class="tsd-signature-keyword">readonly</span> {" "} </> )}
  • partials/typeDetails.tsx(第 388–393 行)中也有完全相同的渲染逻辑,用于参数索引签名。

也就是说:isReadonly标志一旦置位,文档签名前就会出现readonly关键字,让读者一眼看出该成员不可写。

测试用例验证

仓库在 readonlyTag.ts 中提供了覆盖@readonly行为的测试样例,包含两种典型用法:

export class Book { /** * Technically property has a setter, but for documentation purposes it should * be presented as readonly. * @readonly */ get title(): string { return "hah"; } set title(_value: string) { throw new Error("This property is read-only!"); } /** * Should be documented as readonly because no consumer should change it. * @readonly */ author!: string; }

该测试用例与原文档示例相互印证,覆盖了两个典型场景:

  1. 含 setter 的属性:title在类型层面可写(存在 setter),但通过@readonly声明为文档只读;
  2. 类属性字段:author使用!断言(definite assignment assertion),本身是可赋值的,同样通过@readonly在文档中呈现为只读。

使用建议与注意事项

适用场景

  • API 设计中的“防御性只读”:属性虽然出于实现原因保留了 setter,但设计上禁止外部修改(如内部状态、缓存值)。此时用@readonly向文档读者明确传达契约;
  • 避免误导的类型系统表达:当 TypeScript 的类型信息无法表达“不可变”语义(例如定义了 setter 但会抛错、或使用!断言声明的字段),@readonly是补充文档语义的正确工具;
  • 索引签名:对于索引签名(index signature),Readonly 标志同样会被渲染为readonly关键字,可配合使用。

注意事项

  • @readonly只影响 TypeDoc 的文档输出,不会改变 TypeScript 的类型检查行为,不要用它替代readonly修饰符或Readonly<T>类型工具;
  • 标记了@readonly的访问器的setter 会从文档中完全移除,这是预期行为而非 bug(见 CommentPlugin.ts 的隐藏逻辑);
  • 与@private、@sealed等一样,它属于修饰符标签,会在转换阶段被消费并从注释中移除,不会残留在渲染文本中。

小结

@readonly是 TypeDoc 修饰符标签家族中一个简洁但实用的工具:通过一行注释即可覆盖 TypeScript 的可写性判断,将成员在文档中呈现为只读,并自动隐藏对应的 setter。其完整链路——从 CommentPlugin.ts 的标志设置、解决阶段的 setter 隐藏,到默认主题模板中的readonly关键字渲染——都体现了 TypeDoc “以注释驱动、以类型为基础”的文档生成理念。当你的 API 存在“类型可写但契约只读”的成员时,@readonly就是表达该契约的标准方式。

  • 开发工具
  • 文档

【免费下载链接】typedoc

Documentation generator for TypeScript projects.

项目地址:https://gitcode.com/gh_mirrors/ty/typedoc
点击查看免费下载
上一篇:munder-difflin 时间窗口技能解析:last30Days 如何把"近 30 天"解析为精确的 ISO 日期范围
下一篇:终极指南:ViewAnimator从iOS 8到iOS 15的跨版本适配要点

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询