ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Angular Signal Forms:从 goldens API 报告解析 @angular/forms_signals 的完整公开 API

Angular Signal Forms:从 goldens API 报告解析 @angular/forms_signals 的完整公开 API Angular Signal Forms从 goldens API 报告解析 angular/forms_signals 的完整公开 API【免费下载链接】angularDeliver web apps with confidence 项目地址: https://gitcode.com/GitHub_Trending/an/angular在 Angular 仓库中goldens/public-api/forms/signals/index.api.md是由 API Extractor 生成的angular/forms_signals包的 API 报告golden 文件它以 TypeScript 声明的形式完整固化了 Signal Forms 这一套“以 signal 为核心”的表单 API 的公开契约form()、schema()、各类验证规则、submit()、FormField/FormRoot指令以及配套的FieldTree/FieldState类型系统。读完本文你将能够基于这份 API 报告准确识别每个公开符号的签名与用途结合 源码实现 理解表单如何以模型为唯一数据源以及在实际项目中组装可验证、可提交、可防抖的 Signal Forms 应用。这份 goldens 文件是什么API 报告的首行声明了它属于哪个包API Report File for angular/forms_signals该报告位于 goldens/public-api/forms/signals/index.api.md与同目录下的 compat/ 子目录共同锁定packages/forms/signals的公开 API 面。仓库中用 golden 文件做回归校验的意义在于一旦开发者改动了angular/forms_signals的公开符号新增、删除、改名、改签名报告就会与源码产生 diff从而在 CI 中显式暴露 API 破坏性变更。对应源码包位于 packages/forms/signals其 PACKAGE.md 说明了该包定位This directory contains the signal-based Angular forms API, built on top of signals. It is an alternative to template-driven and reactive forms that keeps signals at its core, and interoperates with the existingangular/formsAPIs.同时该文档列出了当时的能力边界未支持项验证防抖、动态对象Dynamic objects、元组Tuples。公开 API 的真正入口是 public_api.ts它依次导出断言、控制、DI、规则含防抖与元数据、验证错误、结构、transformedValue、类型以及FormField、FormRoot两个指令index.ts 则只是用于编辑与构建校验的转发文件。源码中所有公开符号标注了publicApi 22.0说明 Signal Forms 是 Angular 22.0 引入的正式 API。API 总览结构函数与类型体系从 API 报告可以按“结构 → 逻辑 → 验证 → 提交 → 模板绑定 → 错误类型”六个维度梳理公开符号。结构层form、schema、apply 系列报告中的结构类符号均标注// publicexport function formTModel(model: WritableSignalTModel): FieldTreeTModel; export function formTModel(model: WritableSignalTModel, schemaOrOptions: SchemaOrSchemaFnTModel | FormOptionsTModel): FieldTreeTModel; export function formTModel(model: WritableSignalTModel, schema: SchemaOrSchemaFnTModel, options: FormOptionsTModel): FieldTreeTModel; export function schemaTValue(fn: SchemaFnTValue): SchemaTValue; export function applyTValue(path: SchemaPathTValue, schema: NoInferSchemaOrSchemaFnTValue): void; export function applyEachTValue extends ReadonlyArrayany(path: SchemaPathTValue, schema: NoInferSchemaOrSchemaFnTValue[number], PathKind.Item): void; export function applyWhenTValue(path: SchemaPathTValue, logic: LogicFnTValue, boolean, schema: NoInferSchemaOrSchemaFnTValue): void; export function applyWhenValueTValue, TNarrowed extends TValue(path: SchemaPathTValue, predicate: (value: TValue) value is TNarrowed, schema: SchemaOrSchemaFnTNarrowed): void; export type FieldTValue, TKey extends string | number string | number () FieldStateTValue, TKey;form()的语义在 structure.ts 的文档注释中讲得非常清楚它把WritableSignalTModel包成一个FieldTreeTModel且form 不维护自己的数据副本——更新FieldState会直接写回原始模型。注释中的官方示例const nameModel signal({first: , last: }); const nameForm form(nameModel); nameForm.first().value.set(John); nameForm().value(); // {first: John, last: } nameModel(); // {first: John, last: }结合源码实现可以看到form()的调用链structure.ts先通过normalizeFormArgs归一化参数再用runInInjectionContext在给定注入器options.injector缺省为当前注入上下文中调用SchemaImpl.rootCompile(schema)编译 schema随后创建FormFieldManager和根FieldNode并注册“字段管理 effect”。若配置了experimentalWebMcpTool还会尝试注入REGISTER_WEBMCP_FORM把表单注册为 WebMCP 工具未启用时开发模式会抛出带provideExperimentalWebMcpForms()提示的错误。apply/applyEach/applyWhen/applyWhenValue四个组合函数对应 schema 的可复用性需求apply把预定义Schema挂到某个路径上实现为pathNode.mergeIn(SchemaImpl.create(schema))applyEach作用于数组字段的每个元素内部用DYNAMIC动态路径解包applyWhen按LogicFn返回值条件启用applyWhenValue则进一步支持类型谓词做类型收窄其普通布尔重载本质是applyWhen(path, ({value}) predicate(value()), schema)的封装。FormOptionsTModel接口的可选字段为injectorDI 上下文、name用于生成字段name属性、submissionFormSubmitOptions、experimentalWebMcpTool{name, description}实验性。类型层SchemaPath、FieldTree、FieldState、FieldContext这是报告中篇幅最大的部分也是理解整套 API 的钥匙定义源头是 types.ts。SchemaPathschema 函数接收的参数类型代表“表单创建前”字段树中的位置。由于FieldPath在表单创建之前就存在因此它不能访问任何字段状态export type SchemaPathTValue, TSupportsRules extends SchemaPathRules SchemaPathRules.Supported, TPathKind extends PathKind PathKind.Root { [ɵɵTYPE]: { value: () TValue; supportsRules: TSupportsRules; pathKind: TPathKind; }; };SchemaPathRules用字面量类型Supported 1/Unsupported 2区分“可挂规则的路径”和“不可挂规则的路径”如兼容模式下的CompatSchemaPath。PathKind的Root/Child/Item三级层级决定了规则函数拿到的是哪种FieldContext。FieldTree表单结构类型镜像数据模型形状并叠加字段状态访问。源码中的注释解释了为何要用[TModel] extends [AbstractControl]这样的“元组包裹”写法——防止条件类型在递归联合类型上分发导致无限类型递归。其结构为(() [TModel] extends [AbstractControl] ? CompatFieldStateTModel, TKey, TMode : FieldStateByModeTModel, TKey, TMode) (TModel extends AbstractControl ? object : TModel extends ReadonlyArrayinfer U ? ReadonlyArrayLikeMaybeFieldTreeU, number, TMode : TModel extends Recordstring, any ? SubfieldsTModel, TMode : object);即调用它拿到FieldState若是数组模型则呈现只读数组形态若是对象模型则呈现Subfields可遍历的子字段映射跳过Function类型的属性。ReadonlyFieldTree只是TMode固定为readonly的别名。FieldState / ReadonlyFieldState字段状态的核心接口。ReadonlyFieldState暴露一组只读信号value、controlValue、disabled、min/max、minLength/maxLength、name、pattern、readonly、required、touched、dirty、hidden、disabledReasons、errors、errorSummary、valid、invalid、pending、submitting、keyInParent、formFieldBindings以及方法metadata()、hasMetadata()、focusBoundControl()。可写的FieldState在此基础上把value/controlValue提升为WritableSignal并新增markAsDirty()、markAsTouched(options?)MarkAsTouchedOptions支持skipDescendants、getError(kind)响应式kind可精确匹配NgValidationError[kind]以收窄错误类型、reset(value?)、reloadValidation()。源码注释特别澄清了valid与invalid的非互反关系某字段有 3 个验证器、2 个无错、1 个 pending 时valid()与invalid()均为false——这是 Signal Forms 状态机设计的核心特征。FieldContext规则/验证函数的入参按PathKind分层export type FieldContextTValue, TPathKind extends PathKind PathKind.Root TPathKind extends PathKind.Item ? ItemFieldContextTValue : TPathKind extends PathKind.Child ? ChildFieldContextTValue : RootFieldContextTValue;RootFieldContext提供value、state、fieldTree、valueOf(path)读其它字段的值、stateOf(path)读其它字段状态含CompatSchemaPath重载、fieldTreeOf(path)、pathKeysChildFieldContext增加key: SignalstringItemFieldContext再增加index: Signalnumber。这套valueOf/stateOf是跨字段逻辑cross-field logic的基础设施。内置验证规则一览报告中的规则函数均可在 src/api/rules/ 找到实现导出索引见 validation/index.ts函数签名要点对应错误类kindrequired(path, config?)BaseValidatorConfig {when?: LogicFn}RequiredValidationErrorrequiredemail(path, config?)作用于string路径EmailValidationErroremailpattern(path, pattern, config?)RegExp \| LogicFnstring\|undefined, RegExp\|undefinedPatternValidationErrorpattern带pattern属性min(path, minValue, config?)/max(path, maxValue, config?)作用于number \| null限值可为LogicFn动态计算Min/MaxValidationErrormin/max带限值属性minLength/maxLength作用于ValueWithLengthOrSizeMin/MaxLengthValidationErrorminLength/maxLengthminDate/maxDate作用于Date \| null限值可为Date \| LogicFnMin/MaxDateValidationErrorminDate/maxDatevalidate(path, logic)FieldValidatorTValue单字段验证自定义ValidationErrorvalidateTree(path, logic)TreeValidatorTValue可为子字段定向报错自定义可带fieldTreevalidateAsync(path, opts)基于Resource的异步验证AsyncValidatorOptions中onError/onSuccess决定validateHttp(path, opts)基于angular/common/http资源请求同上HttpValidatorOptionsvalidateStandardSchema(path, schema)接入standard-schema/specZod 等StandardSchemaValidationErrorstandardSchema带issue属性所有规则函数都遵循统一签名范式第一个参数是SchemaPath约束为SchemaPathRules.Supported的路径第三个参数BaseValidatorConfig允许指定message等配置许多规则支持when条件required、disabled、hidden、readonly、validateAsync、validateHttp均有when选项LogicFnTValue, boolean。validateAsync的AsyncValidatorOptions是最重的配置对象params(ctx) TParams声明依赖参数验证在参数变化时重新触发、factory: (params: SignalTParams | undefined) ResourceTResult | undefined返回一个Resource、onSuccess把结果映射为TreeValidationResult、onError处理失败、可选debounce?: DebounceTimer。HttpValidatorOptions则是其 HTTP 专用变体request(ctx) string | HttpResourceRequest | undefined、options?: HttpResourceOptions二者同样支持when与debounce。从类型结构看异步验证与angular/core的Resource及DebounceTimer深度绑定——验证被建模为资源请求而非回调。防抖debounce 与 Debouncerexport function debounceTValue, TPathKind extends PathKind PathKind.Root( path: SchemaPathTValue, SchemaPathRules.Supported, TPathKind, config: number | blur | DebouncerTValue, TPathKind): void; export type DebouncerTValue, TPathKind extends PathKind PathKind.Root (context: FieldContextTValue, TPathKind, abortSignal: AbortSignal) Promisevoid | void;实现见 debounce.tsdebounce把配置归一化为Debouncer后以元数据规则DEBOUNCER挂到路径节点上。归一化逻辑很清晰——函数原样返回blur返回一个“直到 abort 信号才 resolve”的 debouncer依赖节点在控件 blur 时同步挂起的更新正数返回基于setTimeoutAbortSignal的计时器 debouncer0表示同步更新。文档注释强调应用该规则后“UI 对模型的更新会延迟直到字段失焦或最近一次防抖更新 resolve”。这与ReadonlyFieldState中value与controlValue的分工呼应controlValue不受防抖影响用于缓冲控件到字段的延迟更新。元数据metadata 与 Limit Keys报告中的元数据 APIexport function metadataTValue, TKey extends MetadataKeyany, any, any, TPathKind extends PathKind PathKind.Root( path: SchemaPathTValue, SchemaPathRules.Supported, TPathKind, key: TKey, logic: NoInferLogicFnTValue, TKey extends LimitSelectionKey ? LimitKeyTValue : MetadataSetterTypeTKey, TPathKind): TKey; export class MetadataKeyTRead, TWrite, TAcc { readonly create: ((state: FieldStateunknown, data: SignalTAcc) TRead) | undefined; readonly reducer: MetadataReducerTAcc, TWrite; } export interface MetadataReducerTAcc, TItem { getInitial: () TAcc; reduce: (acc: TAcc, item: TItem) TAcc; }内置元数据键即报告里的一组constREQUIRED: MetadataKeySignalboolean, boolean, boolean限制类MIN_NUMBER、MAX_NUMBER、MIN_LENGTH、MAX_LENGTH、MIN_DATE、MAX_DATE类型均为LimitKeyT正则类PATTERN: MetadataKeySignalRegExp[], RegExp | undefined, RegExp[]以及供自定义使用的工厂createMetadataKey()/createManagedMetadataKey(create, reducer?)。MetadataReducer命名空间静态提供了list、min、max、or、and、override六种归约器。LimitKey/LimitSelectionKey与MIN/MAX/createLimitSelectionKey()配合可以把“最小/最大值”这类元数据作为共享约束在字段间传播。内置规则min/max/pattern等本质上是这些元数据键的语法糖它们写入元数据同时驱动验证ReadonlyFieldState上暴露的min、maxLength、pattern等信号正是元数据的派生视图并可用于自动同步原生控件属性。禁用与只读disabled、hidden、readonlyexport function disabledTValue, TPathKind(path: SchemaPath..., config?: { when?: string | NoInferLogicFnTValue, boolean | string, TPathKind }): void; export function hiddenTValue, TPathKind(path: SchemaPath..., config?: { when?: NoInferLogicFnTValue, boolean, TPathKind }): void; export function readonlyTValue, TPathKind(path: SchemaPath..., config?: { when?: NoInferLogicFnTValue, boolean, TPathKind }): void;三者均提供“新签名”第二个参数为{when}配置对象和一个标注// public deprecated的旧签名直接传logic这是典型的 API 平滑演进先保留旧调用方式再用对象配置形式做前向兼容。hidden的语义在 types.ts 注释中明确字段被 hidden 时不参与 valid/touched/dirty 判定但模板隐藏需要自行用if (!field.hidden())完成。disabled支持string形式的when对应DisabledReason{fieldTree, message?}与状态信号disabledReasons: Signalreadonly DisabledReason[]用于表达“因为哪个字段不满足条件而被禁用”。提交层submit 与 FormRoot报告中的提交相关符号export function submitTModel(form: FieldTreeTModel, options?: NoInferFormSubmitOptionsunknown, TModel): Promiseboolean; export function submitTModel(form: FieldTreeTModel, action: NoInferFormSubmitOptionsunknown, TModel[action]): Promiseboolean; export interface FormSubmitOptionsTRootModel, TSubmittedModel { action: (field: FieldTreeTRootModel TSubmittedModel, detail: { root: FieldTreeTRootModel; submitted: FieldTreeTSubmittedModel }) PromiseTreeValidationResult; ignoreValidators?: pending | none | all; onInvalid?: (field: FieldTreeTRootModel TSubmittedModel, detail: { root: FieldTreeTRootModel; submitted: FieldTreeTSubmittedModel }) void; }FormSubmitOptions.ignoreValidators的三档语义在 types.ts 注释中写明pending默认——没有 invalid 验证器即可提交pending 不阻塞none——所有验证器必须通过pending 阻塞提交all——无论 invalid 还是 pending 都照提。structure.ts 的实现印证了完整流程untracked(node.submitState.submitting)为真时直接返回false——并发提交被禁止归一化 options函数形式包装为{action}缺省回退到表单创建时的submitOptions没有 action 时抛出MISSING_SUBMIT_ACTION运行时错误node.markAsTouched()先把字段标记为已触碰shouldRunAction按ignoreValidators判定是否执行 action不执行时调用onInvalidaction 返回的TreeValidationResult经由setSubmissionErrors按error.fieldTree定位到具体字段写入submitState.submissionErrors——服务端错误因此能精确落到对应字段的errors上。官方示例摘自源码 JSDoc展示了服务端错误如何回流const registrationForm form(signal({username: god, password: })); submit(registrationForm, { action: async (f) { return registerNewUser(registrationForm); // 返回带 fieldTree 的 ValidationError 数组 } }); registrationForm.username().errors(); // [{kind: server, message: Username already taken}]模板侧由FormRoot指令衔接FormRoot声明在form[formRoot]选择器上host 自动加novalidate并监听(submit)form_root.ts 中onSubmit调用preventDefault()且仅当表单创建时提供了 submission options才调用submit()。测试侧可见 form_root.spec.ts 与 form.spec.ts 对该行为的覆盖。模板绑定层FormField、FormValueControl、FormCheckboxControl报告中的 UI 绑定符号export class FormFieldT { readonly element: HTMLElement; readonly errors: SignalValidationError.WithFieldTree[]; readonly field: i0.InputSignalFieldT; focus(options?: FocusOptions): void; readonly injector: Injector; registerAsBinding(bindingOptions?: FormFieldBindingOptions): void; reset(): void; readonly state: SignalFieldStateT, string | number; static ɵdir: i0.ɵɵDirectiveDeclarationFormFieldany, [formField], [formField], ...; } export interface FormValueControlTValue extends FormUiControlTValue { readonly value: ModelSignalTValue; readonly checked?: undefined; } export interface FormCheckboxControl extends FormUiControlboolean { readonly checked: ModelSignalboolean; readonly value?: undefined; }FormField选择器[formField]field为必填 signal input别名formField是绑定指令FormValueControl/FormCheckboxControl则定义了“自定义控件”必须暴露的接口形态以ModelSignal承载value/checked配合FormUiControl中一系列可选InputSignaldirty、disabled、disabledReasons、errors、hidden、invalid、max、maxLength、min、minLength、name、pattern、pending、readonly、required、touched与touch: OutputRefvoid。这解释了为什么信号表单能与自定义组件日期选择器、富文本等协作组件只需满足FormValueControl形状即可被FormField识别并登记为FormFieldBindingelement、injector、state、focus()。FormFieldBindingOptions允许控件自定义focus/reset行为。FORM_FIELD: InjectionTokenFormFieldunknown与isFieldTree(value): value is FieldTreeunknown提供了 DI 查找与类型守卫能力。错误类型体系报告的错误侧 API 分为三部分基础接口与工厂ValidationError {kind, message?}、BaseNgValidationErrorfieldTreekind 可选messageValidationErrorOptions {message?}。带 fieldTree 的工厂函数requiredError、emailError、minError(min, options)、maxError、minError、maxLengthError、minLengthError、minDateError(date, options)、maxDateError、patternError(pattern, options)、standardSchemaError(issue, options)各有(options: WithFieldTree...)与(options?: ...)两个重载分别返回带/不带fieldTree的错误对象。类型修饰工具WithFieldTreeT、WithOptionalFieldTreeT、WithoutFieldTreeT以及ValidationError命名空间内的WithFieldTree/WithFormField/WithOptionalFieldTree/WithoutFieldTree接口旧的WithField等别名已标注deprecatedNgValidationError是全部内置错误类的可辨识联合RequiredValidationError | MinValidationError | MinDateValidationError | MaxValidationError | MaxDateValidationError | MinLengthValidationError | MaxLengthValidationError | PatternValidationError | EmailValidationError | StandardSchemaValidationError | NativeInputParseError其kind字符串字面量即getError()精确重载的匹配键。NativeInputParseErrorkind parse对应原生输入解析失败。TreeValidationResult与ValidationResult、AsyncValidationResult三个结果类型的差别在于错误是否需要显式声明目标字段TreeValidationResult允许省略fieldTree默认落在当前字段ValidationResult要求每个错误都显式带fieldTreeAsyncValidationResult再叠加pending态。这套区分直接服务于validateTree/validate/validateAsync三个函数的返回类型。互操作、解析与配置旧表单互操作CompatFieldStateTControl在FieldStateByMode之上追加control: SignalTControlCompatSchemaPath标记SchemaPathRules.Unsupported兼容路径不挂规则ReadonlyCompatFieldState为其只读别名FieldContext的stateOf(p)针对CompatSchemaPath有专门重载能从AbstractControl路径解包出CompatFieldState。对应测试见 compat.spec.ts 与 signal_form_control.spec.ts实现位于 compat/ 子包。解析错误NativeInputParseErrorkind parse与ParseResultTValue {value?, error?}配合transformedValue(value: ModelSignalTValue, options: {format, parse}): TransformedValueSignalTRaw后者在WritableSignalTRaw上附加parseErrors: Signalreadonly ValidationError.WithoutFieldTree[]实现“显示值/模型值”的双向转换与解析错误收集实现见 transformed_value.ts行为测试见 parse_errors.spec.ts。应用级配置provideSignalFormsConfig(config: SignalFormsConfig): Provider[]注入SignalFormsConfig {classes?: { [className: string]: (formField: FormFieldBinding) boolean }}用于按字段绑定状态自动挂 CSS 状态类实现见 di.ts直接把配置写入SIGNAL_FORMS_CONFIGtoken。WebMCP 实验能力provideExperimentalWebMcpForms(): EnvironmentProviders与FormOptions.experimentalWebMcpTool、IS_ASYNC_VALIDATION_RESOURCE符号共同构成实验性 AI 工具集成面。阅读 goldens 报告的实用建议以报告核对升级goldens/public-api/forms/signals/是angular/forms_signals的公开契约快照deprecated标记如disabled/hidden/readonly的旧签名、ValidationError.WithField等别名是升级迁移的直接线索以源码注释补全语义报告只保留签名参数语义、示例与see链接都在 src/api/ 的 JSDoc 中例如form()的数据源语义、valid/invalid的 pending 语义以测试用例验证行为test/node/ 覆盖结构、schema、验证器、防抖、提交等纯逻辑行为test/web/ 覆盖FormField绑定、聚焦、自定义控件等浏览器行为注意适用前提该 API 自publicApi 22.0起为正式 APIexperimentalWebMcpTool/provideExperimentalWebMcpForms标注为实验性angular/forms包的 package.json 还引入了standard-schema/spec与zod作为标准 Schema 验证的依赖基础。综合来看这份 API 报告呈现的是一套“模型即信号、schema 即规则、字段即代理”的完整表单体系form()绑定WritableSignal模型并返回FieldTreeschema 函数通过SchemaPath声明式挂载验证、禁用、防抖与元数据规则FieldState以一组信号暴露完整字段状态submit与FormRoot/FormField完成提交与模板闭环而CompatFieldState等互操作类型保证了与既有angular/forms体系的平滑过渡。【免费下载链接】angularDeliver web apps with confidence 项目地址: https://gitcode.com/GitHub_Trending/an/angular创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表