深入解析 Angular 的 `@angular/common` 公共 API:从 golden API 报告看通用指令、管道与工具库的全貌
导读
@angular/common 是 Angular 框架中"最常用"的基础包——我们在模板里写的 *ngIf、*ngFor,格式化日期的 date 管道,页面路由所需的 Location 与 LocationStrategy,乃至现代化图片优化指令 NgOptimizedImage,全部定义于此。本篇文章以当前仓库中的权威 API 契约文档 goldens/public-api/common/index.api.md 为骨架,逐类解读这份由 API Extractor 自动生成的 @angular/common 公共 API 报告:如何读懂 @public / @deprecated / (undocumented) 标记,四大功能族(结构型指令、内置管道、i18n 格式化工具、Location 导航底层)各暴露了哪些符号与签名,哪些接口是过时/已弃用需要迁移的,以及如何通过 pnpm public-api:check / pnpm public-api:update 验证并更新这份契约。读完你会具备一份可随时对照源码使用的 @angular/common API 速查手册。
这份文档是什么:@angular/common 的 golden API 报告
goldens/public-api/common/index.api.md 的正文第一行即声明其性质:
API Report File for "@angular/common" —— Do not edit this file. It is a report generated by API Extractor.
它是一份机器生成、严禁手改的公共 API 契约文件(golden file),其作用相当于 @angular/common 对外发布面的"快照与金丝雀":
- 生成来源:由 Microsoft 的 API Extractor 工具对编译产物扫描生成。文件内的 TS 代码块逐条记录了每个被标记为
@publicApi的导出符号的类型签名。 - 变更守门员:目录说明见 goldens/README.md —— 仓库"在每次 PR 与提交时作为 Bazel 测试的一部分"运行校验。任何人若无意改变了公共 API(新增、删除、改名、改签名),测试都会失败,从而保证发布到 npm 的包面是可控的。
- 验证与刷新命令:按 goldens/README.md 的说明,本地校验或(在有意变更 API 后)刷新 golden 使用:
pnpm public-api:check # 校验当前源码导出与 golden 一致
pnpm public-api:update # 用当前导出结果覆盖刷新 golden
从源码侧看,这份报告的导出面由 packages/common/src/common.ts 这个"总出口"统一编排,再经 packages/common/index.ts → packages/common/public_api.ts 暴露;而 npm 元信息(包描述 "Angular - commonly needed directives and services"、peerDependencies 要求 @angular/core 与 rxjs ^6.5.3 || ^7.4.0、Node 引擎版本等)位于 packages/common/package.json。
读这份报告前必须知道的 4 类标记
// @public:稳定公共 API,可放心使用,也是 golden 保护的对象。// @public @deprecated:仍被导出以向后兼容,但官方已建议迁移。本文件中NgIf、NgForOf、NgSwitch、DatePipe的时间戳旧令牌、全部getLocale*系列查询函数等都带有该标记。(undocumented):该符号没有 JSDoc 文档注释,仅代表"文档缺失",不代表内部实现——它们同样属于公共面。- 静态字段
ɵfac/ɵprov/ɵdir/ɵpipe/ɵmod/ɵinj:Angular AOT 编译器为组件/指令/管道/模块生成的编译期元数据声明。例如DatePipe的ɵpipe显示为i0.ɵɵPipeDeclaration<DatePipe, "date", true>,说明它注册为模板名date;ɵfac中的{optional: true}表示构造参数可空注入(如 DatePipe 的默认时区参数)。日常开发无需直接使用它们,但读 API 报告时它们能佐证"该符号确实是指令/管道/服务"。
另外注意报告中的别名导出技巧:当类型名与内部实现名冲突时,报告会以 Location_2、NgForOf、PopStateEvent_2 形式显示再 export { ... as Location } 等;同时 DOCUMENT、IMAGE_CONFIG、ImageConfig 三个符号直接以 export { DOCUMENT } 的方式从 @angular/core 再导出(见报告 import 区与文件尾部),这说明它们的主人是 core 包,@angular/common 只是向前兼容地转发。
CommonModule:所有指令与管道的聚合入口
报告里的 CommonModule 类本身几乎无方法,关键信息集中在它的 ɵinj / ɵmod 声明中。对照 packages/common/src/common_module.ts 的实现可以确认:它是一个空壳 @NgModule,只做一件事——imports: [COMMON_DIRECTIVES, COMMON_PIPES] 并原样 exports。
也就是说,只要在模块(或在 standalone 组件中 imports)引入 CommonModule,就可以一次性获得全部内置指令与管道。从报告里 ɵmod 的声明可以数出它导出的完整名单:
- 指令(10 个):
NgClass、NgComponentOutlet、NgForOf、NgIf、NgTemplateOutlet、NgStyle、NgSwitch、NgSwitchCase、NgSwitchDefault、NgPlural、NgPluralCase; - 管道(14 个):
AsyncPipe、UpperCasePipe、LowerCasePipe、JsonPipe、SlicePipe、DecimalPipe、PercentPipe、TitleCasePipe、CurrencyPipe、DatePipe、I18nPluralPipe、I18nSelectPipe、KeyValuePipe。
报告特意注明该模块不包含 Location 相关 Provider("does not contain the location providers"),因为这些服务需要平台相关的实现(浏览器历史 API vs. 服务器环境),通常由 @angular/platform-browser 的 BrowserModule 负责装配——这也是"新建 CLI 项目时 BrowserModule 会被自动包含"的原因。
结构型指令家族:条件渲染、循环、样式绑定与动态组件
该组指令的源码位于 packages/common/src/directives。报告给出了每个指令的输入(ɵdir 中 alias 即模板属性名)与 required 标记,可用于精确的模板写法参考。
NgClass 与 NgStyle:动态 class / style 绑定
两者都实现 DoCheck,构造参数为 ElementRef + Renderer2(NgStyle 还额外注入 KeyValueDiffers 做变更检测优化)。NgClass 的 ɵdir 选择器是 [ngClass],它把宿主元素的 class 属性也接收为输入 klass(alias class)。模板可用以下任一形态喂给 ngClass:
- 字符串:
ngClass="foo bar"; - 数组:
ngClass="['foo', 'bar']"; Set<string>;- 键值对象:
{ 'foo': isFoo }。
NgIf / NgForOf / NgSwitch*:已被内置控制流取代(@deprecated)
这是本报告中最重要的迁移信号:NgIf、NgForOf、NgSwitch、NgSwitchCase、NgSwitchDefault 全部被标记为 @deprecated。但它们的类与辅助类型仍保留并被 CommonModule 导出,以兼容存量代码:
NgIf:模板守卫ngTemplateGuard_ngIf: 'binding'允许窄化类型(ngIf为false | 0 | '' | null | undefined时上下文被Exclude),配合ngIfThen/ngIfElse模板引用与上下文类NgIfContext(含$implicit与ngIf属性)。NgForOf(导出别名为NgFor):类型签名NgForOf<T, U extends NgIterable<T>>,支持ngForOf、ngForTrackBy: TrackByFunction<T>(性能优化必配)、ngForTemplate;上下文类NgForOfContext提供$implicit、index、count及派生属性first/last/even/odd。NgSwitch体系由三件套组成:宿主[ngSwitch]、匹配分支[ngSwitchCase]、兜底[ngSwitchDefault]。
若你正在编写新代码,应优先采用 Angular 内置的 @if / @for / @switch 块语法;*ngIf、*ngFor、[ngSwitch] 仅用于维护遗留代码。
NgPlural / NgPluralCase:复数规则分支
两者都依赖 NgLocalization(基类,只声明抽象方法 getPluralCategory(value, locale?))。默认实现 NgLocaleLocalization 依据 CLDR 复数分类(zero / one / two / few / many / other,见 Plural 枚举)决定显示哪条分支,用于"1 item / 2 items"这类国际化文案;ɵfac 显示 NgPluralCase 的值来自宿主元素属性 ngPluralCase。
NgTemplateOutlet 与 NgComponentOutlet:模板与组件的动态插入
NgTemplateOutlet<C>(源码 ng_template_outlet.ts)接收三个输入:ngTemplateOutlet: TemplateRef<C>、ngTemplateOutletContext($implicit语义的上下文数据)、ngTemplateOutletInjector(可传'outlet'字面量以继承宿主注入器)。NgComponentOutlet<T>在 v17+ 之后的签名体现了现代 standalone 生态:除核心ngComponentOutlet: Type<T>外,还支持ngComponentOutletInputs?: Record<string, unknown>(直接以键值对象注入组件输入,等价@Input绑定)、ngComponentOutletInjector、ngComponentOutletEnvironmentInjector、ngComponentOutletContent(投影内容节点)、ngComponentOutletNgModule,并提供只读 gettercomponentInstance访问动态创建出的组件实例。
内置管道(Pipes):模板数据变换工具箱
管道实现集中于 packages/common/src/pipes,全部为 standalone 管道(ɵpipe 声明第三参为 true),可脱离模块直接 imports 使用。每个管道的 transform 都按 TypeScript 重载分列了"常规输入"与"null / undefined 输入",后者一律返回 null——这是 Angular 管道对空值友好的统一约定。
| 管道(模板名) | 核心签名 | 说明 |
|---|---|---|
AsyncPipe(async) |
`transform(obj: Observable | Subscribable |
UpperCasePipe / LowerCasePipe |
(value: string): string |
大小写转换 |
TitleCasePipe |
(value: string): string |
每个词首字母大写 |
JsonPipe |
(value: unknown): string |
JSON.stringify 的模板封装,调试利器 |
SlicePipe |
数组 / 字符串切片 (value, start, end?) |
语义类似 Array.prototype.slice / String.prototype.slice,支持负索引 |
DecimalPipe(number) |
(value: number | string, digitsInfo?, locale?): string |
数字分组与精度,digitsInfo 形如 "1.2-2"(minIntegerDigits.minFractionDigits-maxFractionDigits) |
PercentPipe(percent) |
(value: number | string, digitsInfo?, locale?): string |
数字乘以 100 后带 % |
CurrencyPipe(currency) |
(value, currencyCode?, display?, digitsInfo?, locale?): string |
display 可为 'code' | 'symbol' | 'symbol-narrow' | string | boolean,决定输出货币代码还是符号;构造函数可选 _defaultCurrencyCode |
DatePipe(date) |
(value: Date | string | number, format?, timezone?, locale?): string |
见下 |
KeyValuePipe(keyvalue) |
(input: ReadonlyMap | Record, compareFn?): Array<KeyValue> |
把 Map / 对象摊平成 {key, value} 数组以便 @for 遍历,支持自定义 compareFn 排序 |
I18nSelectPipe(i18nSelect) |
(value: string, mapping: {[k]: string}): string |
按键值从映射表挑文案 |
I18nPluralPipe(i18nPlural) |
(value: number, pluralMap: {[count]: string}, locale?): string |
复数文案;底层依赖 NgLocalization.getPluralCategory 决定匹配 =0、=1、other 等键 |
关于 DatePipe 的两组配置令牌
DatePipe 是本包的"重武器",除默认 'mediumDate' 等预置格式外还接受 CLDR 日期格式串。报告中与它相关的令牌值得关注:
DATE_PIPE_DEFAULT_OPTIONS: InjectionToken<DatePipeConfig>:全局默认配置,其中DatePipeConfig接口只有两个可选字段dateFormat?: string与timezone?: string。提供该令牌即可为整个应用的date管道设定统一格式与默认时区(provider 位于应用入口的providers)。DATE_PIPE_DEFAULT_TIMEZONE: InjectionToken<string>:旧版单一时区令牌,已在报告中标记@deprecated,新代码应改用DATE_PIPE_DEFAULT_OPTIONS。
DatePipe 的 ɵfac 显示三个构造参数(locale、可选默认时区、可选默认配置),其中后两者标注 {optional: true},即令牌缺失时自动降级为 CLDR 默认值。
i18n 数字/日期格式化:函数式工具与(已弃用的)Locale 查询 API
不依赖 DI、可在任意 TS 代码中直接调用的纯函数来自 packages/common/src/i18n 下的 format_date.ts、format_number.ts、locale_data_api.ts,在 packages/common/src/common.ts 中统一导出。
四个核心格式化函数
| 函数 | 签名 | 等价管道 |
|---|---|---|
formatDate |
(value: string | number | Date, format: string, locale: string, timezone?: string): string |
date |
formatNumber |
(value: number, locale: string, digitsInfo?: string): string |
number |
formatPercent |
(value: number, locale: string, digitsInfo?: string): string |
percent |
formatCurrency |
(value: number, locale: string, currency: string, currencyCode?: string, digitsInfo?: string): string |
currency |
它们与对应管道共用同一套内部实现(管道只是模板层封装),适合在 Service / Effect / 日志等非模板场景做本地化格式化。
registerLocaleData 与"即将整体退役"的 getLocale* 族
registerLocaleData(data, localeId?, extraData?):运行时把从@angular/common/locales子路径导入的 locale 数据注册进DatePipe/number管道等使用的本地化数据仓库,以实现非全局导入的按需加载。- 报告用极长的篇幅列出约 25 个
getLocale*函数(getLocaleId、getLocaleMonthNames、getLocaleDateFormat、getLocaleFirstDayOfWeek、getLocaleCurrencySymbol、getLocalePluralCase、getNumberOfCurrencyDigits……),它们全部标注@deprecated,连同getCurrencySymbol一起,属于历史遗留的 locale 数据查询 API。新代码如需读取 CLDR 派生数据,应改用@angular/common/locales直接提供的数据结构。 - 支撑这些函数的一批过时枚举/常量也随报告被列出并标记废弃:
FormatWidth(Short=0, Medium=1, Long=2, Full=3)、FormStyle(Format/Standalone)、TranslationWidth(Narrow=0, Abbreviated=1, Wide=2, Short=3)、NumberFormatStyle(Decimal/Percent/Currency/Scientific)、NumberSymbol(含Decimal、Group、MinusSign、PerMille、CurrencyDecimal等 14 个成员)、Plural(Zero/One/Two/Few/Many/Other)、WeekDay(Sunday=0…Saturday=6)、Time({hours, minutes})。使用它们的既有代码应规划迁移,但它们仍被导出,不会立刻中断。 - 未废弃的辅助类型只有少量,例如
getCurrencySymbol(code, 'wide'|'narrow', locale?)之外的NgLocalization/NgLocaleLocalization抽象与默认实现(用于复数管道,前文已述)。
Location 导航家族:URL 读写与路由策略的底层抽象
报告的第二大板块是"导航与地址栏管理",源码见 packages/common/src/location,是整个 @angular/router 依赖浏览器/服务器 URL 行为的桥梁。其层级设计如下:
LocationStrategy(抽象:back/forward/path/prepareExternalUrl/pushState/replaceState/onPopState/getBaseHref/getState/historyGo?)
├── PathLocationStrategy ← 默认策略,HTML5 History API(pushState/replaceState)
│ └── NoTrailingSlashPathLocationStrategy ← 输出 URL 不含尾斜杠
│ └── TrailingSlashPathLocationStrategy ← 输出 URL 强制带尾斜杠
└── HashLocationStrategy ← hash 模式(#/path),适合静态托管
PlatformLocation(抽象:href/hash/pathname/search/hostname/port/protocol 访问器 + onPopState/onHashChange/pushState…)
└── BrowserPlatformLocation ← 浏览器 DOM 实现,含 getBaseHrefFromDOM()
值得逐条记录的关键导出:
Location(报告中以Location_2内部名导出):高层服务,注入LocationStrategy,提供go(path, query?, state?)、replaceState、back/forward/historyGo、isCurrentPathEqualTo、path(includeHash?)、subscribe(onNext)(监听PopStateEvent)以及静态工具joinWithSlash、normalizeQueryParams、stripTrailingSlash、normalize。LocationStrategy与PlatformLocation:抽象基类,真正的平台差异(DOM History API vs. 服务端占位)都被隔离在PlatformLocation的实现中;PlatformLocation同时暴露可取消订阅的onPopState/onHashChange(返回VoidFunction)。PathLocationStrategy构造器(platformLocation, href?)中的href为可选,用于覆盖<base href>探测结果;HashLocationStrategy构造器(platformLocation, baseHref?)同理由ɵfac标为{optional: true}。- 两个新的 URL 规范化策略:
NoTrailingSlashPathLocationStrategy与TrailingSlashPathLocationStrategy仅覆写prepareExternalUrl,用于强制/去除 URL 尾斜杠——适合 SEO 规范或反向代理路由规则严格的部署场景。 - 令牌:
APP_BASE_HREF: InjectionToken<string>(手动指定<base>,供Location计算内部 URL);LOCATION_INITIALIZED: InjectionToken<Promise<any>>(在应用初始化前等待 location 就绪)。 - 事件类型:
PopStateEvent(内部名PopStateEvent_2,可选字段pop? / state? / type? / url?)、LocationChangeEvent(type+state)、监听器类型LocationChangeListener。
浏览器侧的现代导航抽象 PlatformNavigation
报告中还出现一个面向未来 Web 标准的抽象类 PlatformNavigation(源码位于 packages/common/src/navigation),它把浏览器 Navigation API(navigate、reload、traverseTo、entries、canGoBack/canGoForward、currentEntry、transition,以及 oncurrententrychange / onnavigate / onnavigatesuccess / onnavigateerror 等事件处理器)收拢成一个可注入抽象,供浏览器之外的平台(如 SSR)提供兼容实现。它复用了 @angular/core 中一批以 ɵ 前缀的内部类型(ɵNavigation、ɵNavigationResult 等),属于"框架内部走在前沿、未来可能公开"的接口。
NgOptimizedImage:基于 img[ngSrc] 指令的图片加载优化体系
从报告可见,图片优化并非孤立的一个指令,而是一整套公开面(源码目录 packages/common/src/directives/ng_optimized_image):
- 指令
NgOptimizedImage,选择器img[ngSrc]。各输入及其模板 alias:ngSrc(required):源码地址;ngSrcset/sizes:响应式 srcset 与 sizes(ngSrcset可自动基于宽度指令生成);width/height:必须提供以预留布局空间、防 CLS;priority:标记 LCP 首屏图(等价fetchpriority=high且禁用懒加载);loading: 'lazy' | 'eager' | 'auto'、decoding: 'sync' | 'async' | 'auto';fill:填充父容器模式的响应式图;placeholder: boolean | string与placeholderConfig?: ImagePlaceholderConfig({blur?: boolean},指示是否生成模糊占位)——指令内部通过generatePlaceholder/shouldBlurPlaceholder两个受保护方法实现;loaderParams?: {[k: string]: any}:透传给 loader 的自定义参数;disableOptimizedSrcset:关闭自动srcset生成。
- Loader 机制:
IMAGE_LOADER: InjectionToken<ImageLoader>定义 loader 函数类型ImageLoader = (config: ImageLoaderConfig) => string;ImageLoaderConfig包含src、width?、height?、isPlaceholder?、loaderParams?。用户可注入自定义 loader 把ngSrc拼接成 CDN 地址。 - 内置 CDN Loader Provider:
provideCloudinaryLoader(path)、provideCloudflareLoader(path)、provideImgixLoader(path)、provideImageKitLoader(path)、provideNetlifyLoader(path?)(最后一个参数可省略)。provider 只需在应用providers中调用一次。 - 辅助令牌:
PRECONNECT_CHECK_BLOCKLIST: InjectionToken<(string | string[])[]>用于屏蔽对某些域名的自动preconnect检查告警;IMAGE_CONFIG与其类型ImageConfig从@angular/core再导出(该令牌承载全局图片默认配置,如默认断点)。
平台判定、依赖注入令牌与基础设施
剩余导出多属于"跨平台开发基础设施",源码对应 packages/common/src 根目录下的若干小文件:
isPlatformBrowser(platformId)/isPlatformServer(platformId):平台判定函数,通常配合@angular/core的PLATFORM_ID令牌注入使用(内部字符串常量PLATFORM_BROWSER_ID/PLATFORM_SERVER_ID仅以ɵ前缀私有导出,未进公共面)。DOCUMENT:从@angular/core再导出的document注入令牌(SSR 环境安全访问 DOM 的推荐方式)。VERSION: Version:包版本对象(发布时由0.0.0-PLACEHOLDER替换为真实版本号)。XhrFactory:抽象类,唯一方法build(): XMLHttpRequest,是 HTTP 底层 XHR 工厂的可注入抽象。ViewportScroller:抽象滚动服务,方法有getScrollPosition/scrollToPosition(position, options?)/scrollToAnchor(anchor, options?)/setOffset/setHistoryScrollRestoration('auto' | 'manual');其ɵprov声明表明运行时在多态 Provider(BrowserViewportScroller或服务端的NullViewportScroller)间解析,Router 的滚动位置恢复功能正是基于它。- 注入令牌与事件:
APP_BASE_HREF、LOCATION_INITIALIZED(见 Location 一节)、LocationChangeEvent/LocationChangeListener。
一份务实的开发对照清单
把报告读薄,可以沉淀出几条可直接指导日常开发的结论:
- 新模板优先内置控制流:
*ngIf、*ngFor、[ngSwitch]三个指令族在报告中被整体标记@deprecated,新代码应使用@if/@for/@switch;*ngIf配套的then/else用@if/@else更直观。 - 数字与日期管道的扩展能力在令牌与纯函数上:
DATE_PIPE_DEFAULT_OPTIONS(dateFormat+timezone)可统一全局日期默认值;模板之外用formatDate/formatCurrency/formatNumber/formatPercent;新增语言用registerLocaleData+@angular/common/locales。 - 不要在新代码里写
getLocale*:整族函数与FormatWidth/FormStyle/NumberFormatStyle等枚举均已@deprecated,属于纯历史遗留接口。 - URL 尾斜杠策略是开箱即用的:无需自实现
LocationStrategy,直接换用TrailingSlashPathLocationStrategy或NoTrailingSlashPathLocationStrategy即可满足规范要求。 - 图片性能优化走
ngSrc全家桶:NgOptimizedImage+ 一个provide*LoaderProvider + 每张图显式width/height(或fill),是 Angular 官方推荐的图片加载方案,相关令牌IMAGE_LOADER、PRECONNECT_CHECK_BLOCKLIST均可按需定制。
小结
@angular/common 的这份 API 报告虽由机器生成、读起来像"符号清单",但它恰恰是框架契约最精确的呈现:CommonModule 聚合了多少指令与管道、哪些 API 已进入弃用窗口、Location 抽象如何分层、图片优化体系需要注入哪些令牌——全部可以在 goldens/public-api/common/index.api.md 中对照 packages/common/src/common.ts 及其下的 directives / pipes / location / i18n / navigation 源码逐条验明。在阅读与源码实现存疑时,以这份 golden 为准;当你有意变更公共 API 时,记得用 pnpm public-api:update 刷新契约并用 pnpm public-api:check 守护它。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0627
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00