@angular/forms 21.1.0-next.0 → 21.1.0-next.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,11 +1,11 @@
1
1
  /**
2
- * @license Angular v21.1.0-next.0
2
+ * @license Angular v21.1.0-next.2
3
3
  * (c) 2010-2025 Google LLC. https://angular.dev/
4
4
  * License: MIT
5
5
  */
6
6
 
7
7
  import * as i0 from '@angular/core';
8
- import { InjectionToken, ɵControl as _Control, ɵCONTROL as _CONTROL, ɵInteropControl as _InteropControl, ɵFieldState as _FieldState, Signal, Provider, WritableSignal, DestroyableInjector, Injector } from '@angular/core';
8
+ import { InjectionToken, ɵControl as _Control, Injector, ɵCONTROL as _CONTROL, ɵɵcontrolCreate as __controlCreate, ɵcontrolUpdate as _controlUpdate, Signal, ɵFieldState as _FieldState, Provider, WritableSignal, DestroyableInjector } from '@angular/core';
9
9
  import * as _angular_forms from '@angular/forms';
10
10
  import { NgControl, AbstractControl, ValidationErrors, FormControlStatus, ControlValueAccessor, ValidatorFn } from '@angular/forms';
11
11
  import { StandardSchemaV1 } from '@standard-schema/spec';
@@ -69,1003 +69,1043 @@ declare const FIELD: InjectionToken<Field<unknown>>;
69
69
  * @experimental 21.0.0
70
70
  */
71
71
  declare class Field<T> implements _Control<T> {
72
- private readonly injector;
73
- private config;
74
- readonly classes: (readonly [string, i0.Signal<boolean>])[];
72
+ readonly element: HTMLElement;
73
+ readonly injector: Injector;
75
74
  readonly field: i0.InputSignal<FieldTree<T>>;
76
75
  readonly state: i0.Signal<[T] extends [_angular_forms.AbstractControl<any, any, any>] ? CompatFieldState<T, string | number> : FieldState<T, string | number>>;
77
- readonly [_CONTROL]: undefined;
76
+ readonly [_CONTROL]: {
77
+ readonly create: typeof __controlCreate;
78
+ readonly update: typeof _controlUpdate;
79
+ };
80
+ private config;
78
81
  /** Any `ControlValueAccessor` instances provided on the host element. */
79
82
  private readonly controlValueAccessors;
80
83
  /** A lazily instantiated fake `NgControl`. */
81
84
  private interopNgControl;
82
- /** A `ControlValueAccessor`, if configured, for the host component. */
83
- get ɵinteropControl(): _InteropControl | undefined;
84
85
  /** Lazily instantiates a fake `NgControl` for this field. */
85
86
  protected getOrCreateNgControl(): InteropNgControl;
86
- ɵregister(): void;
87
87
  static ɵfac: i0.ɵɵFactoryDeclaration<Field<any>, never>;
88
88
  static ɵdir: i0.ɵɵDirectiveDeclaration<Field<any>, "[field]", never, { "field": { "alias": "field"; "required": true; "isSignal": true; }; }, {}, never, never, true, never>;
89
89
  }
90
90
 
91
91
  /**
92
- * Represents metadata that may be defined on a field when it is created using a `metadata` rule
93
- * in the schema. A particular `MetadataKey` can only be defined on a particular field **once**.
92
+ * Sets a value for the {@link MetadataKey} for this field.
93
+ *
94
+ * This value is combined via a reduce operation defined by the particular key,
95
+ * since multiple rules in the schema might set values for it.
96
+ *
97
+ * @param path The target path to set the metadata for.
98
+ * @param key The metadata key
99
+ * @param logic A function that receives the `FieldContext` and returns a value for the metadata.
100
+ * @template TValue The type of value stored in the field the logic is bound to.
101
+ * @template TKey The type of metadata key.
102
+ * @template TPathKind The kind of path the logic is bound to (a root path, child path, or item of an array)
94
103
  *
95
104
  * @category logic
96
105
  * @experimental 21.0.0
97
106
  */
98
- declare class MetadataKey<TValue> {
99
- private brand;
100
- /** Use {@link createMetadataKey}. */
101
- private constructor();
102
- }
107
+ declare function metadata<TValue, TKey extends MetadataKey<any, any, any>, TPathKind extends PathKind = PathKind.Root>(path: SchemaPath<TValue, SchemaPathRules.Supported, TPathKind>, key: TKey, logic: NoInfer<LogicFn<TValue, MetadataSetterType<TKey>, TPathKind>>): TKey;
103
108
  /**
104
- * Creates a {@link MetadataKey}.
109
+ * A reducer that determines the accumulated value for a metadata key by reducing the individual
110
+ * values contributed from `metadata()` rules.
105
111
  *
106
- * @experimental 21.0.0
112
+ * @template TAcc The accumulated type of the reduce operation.
113
+ * @template TItem The type of the individual items that are reduced over.
114
+ * @experimental 21.0.2
107
115
  */
108
- declare function createMetadataKey<TValue>(): MetadataKey<TValue>;
116
+ interface MetadataReducer<TAcc, TItem> {
117
+ /** The reduce function. */
118
+ reduce: (acc: TAcc, item: TItem) => TAcc;
119
+ /** Gets the initial accumulated value. */
120
+ getInitial: () => TAcc;
121
+ }
122
+ declare const MetadataReducer: {
123
+ /** Creates a reducer that accumulates a list of its individual item values. */
124
+ readonly list: <TItem>() => MetadataReducer<TItem[], TItem | undefined>;
125
+ /** Creates a reducer that accumulates the min of its individual item values. */
126
+ readonly min: () => MetadataReducer<number | undefined, number | undefined>;
127
+ /** Creates a reducer that accumulates a the max of its individual item values. */
128
+ readonly max: () => MetadataReducer<number | undefined, number | undefined>;
129
+ /** Creates a reducer that logically or's its accumulated value with each individual item value. */
130
+ readonly or: () => MetadataReducer<boolean, boolean>;
131
+ /** Creates a reducer that logically and's its accumulated value with each individual item value. */
132
+ readonly and: () => MetadataReducer<boolean, boolean>;
133
+ /** Creates a reducer that always takes the next individual item value as the accumulated value. */
134
+ readonly override: typeof override;
135
+ };
136
+ declare function override<T>(): MetadataReducer<T | undefined, T>;
137
+ declare function override<T>(getInitial: () => T): MetadataReducer<T, T>;
109
138
  /**
110
139
  * Represents metadata that is aggregated from multiple parts according to the key's reducer
111
140
  * function. A value can be contributed to the aggregated value for a field using an
112
- * `aggregateMetadata` rule in the schema. There may be multiple rules in a schema that contribute
113
- * values to the same `AggregateMetadataKey` of the same field.
141
+ * `metadata` rule in the schema. There may be multiple rules in a schema that contribute
142
+ * values to the same `MetadataKey` of the same field.
143
+ *
144
+ * @template TRead The type read from the `FieldState` for this key
145
+ * @template TWrite The type written to this key using the `metadata()` rule
146
+ * @template TAcc The type of the reducer's accumulated value.
114
147
  *
115
148
  * @experimental 21.0.0
116
149
  */
117
- declare class AggregateMetadataKey<TAcc, TItem> {
118
- readonly reduce: (acc: TAcc, item: TItem) => TAcc;
119
- readonly getInitial: () => TAcc;
150
+ declare class MetadataKey<TRead, TWrite, TAcc> {
151
+ readonly reducer: MetadataReducer<TAcc, TWrite>;
152
+ readonly create: ((s: Signal<TAcc>) => TRead) | undefined;
120
153
  private brand;
121
154
  /** Use {@link reducedMetadataKey}. */
122
- private constructor();
155
+ protected constructor(reducer: MetadataReducer<TAcc, TWrite>, create: ((s: Signal<TAcc>) => TRead) | undefined);
123
156
  }
124
157
  /**
125
- * Creates an {@link AggregateMetadataKey} that reduces its individual values into an accumulated
126
- * value using the given `reduce` and `getInitial` functions.
127
- * @param reduce The reducer function.
128
- * @param getInitial A function that gets the initial value for the reduce operation.
158
+ * Extracts the the type that can be set into the given metadata key type using the `metadata()` rule.
129
159
  *
130
- * @experimental 21.0.0
131
- */
132
- declare function reducedMetadataKey<TAcc, TItem>(reduce: (acc: TAcc, item: TItem) => TAcc, getInitial: NoInfer<() => TAcc>): AggregateMetadataKey<TAcc, TItem>;
133
- /**
134
- * Creates an {@link AggregateMetadataKey} that reduces its individual values into a list.
160
+ * @template TKey The `MetadataKey` type
135
161
  *
136
162
  * @experimental 21.0.0
137
163
  */
138
- declare function listMetadataKey<TItem>(): AggregateMetadataKey<TItem[], TItem | undefined>;
164
+ type MetadataSetterType<TKey> = TKey extends MetadataKey<any, infer TWrite, any> ? TWrite : never;
139
165
  /**
140
- * Creates {@link AggregateMetadataKey} that reduces its individual values by taking their min.
166
+ * Creates a metadata key used to contain a computed value.
167
+ * The last value set on a given field tree node overrides any previously set values.
168
+ *
169
+ * @template TWrite The type written to this key using the `metadata()` rule
141
170
  *
142
171
  * @experimental 21.0.0
143
172
  */
144
- declare function minMetadataKey(): AggregateMetadataKey<number | undefined, number | undefined>;
173
+ declare function createMetadataKey<TWrite>(): MetadataKey<Signal<TWrite | undefined>, TWrite, TWrite | undefined>;
145
174
  /**
146
- * Creates {@link AggregateMetadataKey} that reduces its individual values by taking their max.
175
+ * Creates a metadata key used to contain a computed value.
176
+ *
177
+ * @param reducer The reducer used to combine individually set values into the final computed value.
178
+ * @template TWrite The type written to this key using the `metadata()` rule
179
+ * @template TAcc The type of the reducer's accumulated value.
147
180
  *
148
181
  * @experimental 21.0.0
149
182
  */
150
- declare function maxMetadataKey(): AggregateMetadataKey<number | undefined, number | undefined>;
183
+ declare function createMetadataKey<TWrite, TAcc>(reducer: MetadataReducer<TAcc, TWrite>): MetadataKey<Signal<TAcc>, TWrite, TAcc>;
151
184
  /**
152
- * Creates an {@link AggregateMetadataKey} that reduces its individual values by logically or-ing
153
- * them.
185
+ * Creates a metadata key that exposes a managed value based on the accumulated result of the values
186
+ * written to the key. The accumulated value takes the last value set on a given field tree node,
187
+ * overriding any previously set values.
188
+ *
189
+ * @param create A function that receives a signal of the accumulated value and returns the managed
190
+ * value based on it. This function runs during the construction of the `FieldTree` node,
191
+ * and runs in the injection context of that node.
192
+ * @template TRead The type read from the `FieldState` for this key
193
+ * @template TWrite The type written to this key using the `metadata()` rule
154
194
  *
155
195
  * @experimental 21.0.0
156
196
  */
157
- declare function orMetadataKey(): AggregateMetadataKey<boolean, boolean>;
197
+ declare function createManagedMetadataKey<TRead, TWrite>(create: (s: Signal<TWrite | undefined>) => TRead): MetadataKey<TRead, TWrite, TWrite | undefined>;
158
198
  /**
159
- * Creates an {@link AggregateMetadataKey} that reduces its individual values by logically and-ing
160
- * them.
199
+ * Creates a metadata key that exposes a managed value based on the accumulated result of the values
200
+ * written to the key.
201
+ *
202
+ * @param create A function that receives a signal of the accumulated value and returns the managed
203
+ * value based on it. This function runs during the construction of the `FieldTree` node,
204
+ * and runs in the injection context of that node.
205
+ * @param reducer The reducer used to combine individual value written to the key,
206
+ * this will determine the accumulated value that the create function receives.
207
+ * @template TRead The type read from the `FieldState` for this key
208
+ * @template TWrite The type written to this key using the `metadata()` rule
209
+ * @template TAcc The type of the reducer's accumulated value.
161
210
  *
162
211
  * @experimental 21.0.0
163
212
  */
164
- declare function andMetadataKey(): AggregateMetadataKey<boolean, boolean>;
213
+ declare function createManagedMetadataKey<TRead, TWrite, TAcc>(create: (s: Signal<TAcc>) => TRead, reducer: MetadataReducer<TAcc, TWrite>): MetadataKey<TRead, TWrite, TAcc>;
165
214
  /**
166
- * An {@link AggregateMetadataKey} representing whether the field is required.
215
+ * A {@link MetadataKey} representing whether the field is required.
167
216
  *
168
217
  * @category validation
169
218
  * @experimental 21.0.0
170
219
  */
171
- declare const REQUIRED: AggregateMetadataKey<boolean, boolean>;
220
+ declare const REQUIRED: MetadataKey<Signal<boolean>, boolean, boolean>;
172
221
  /**
173
- * An {@link AggregateMetadataKey} representing the min value of the field.
222
+ * A {@link MetadataKey} representing the min value of the field.
174
223
  *
175
224
  * @category validation
176
225
  * @experimental 21.0.0
177
226
  */
178
- declare const MIN: AggregateMetadataKey<number | undefined, number | undefined>;
227
+ declare const MIN: MetadataKey<Signal<number | undefined>, number | undefined, number | undefined>;
179
228
  /**
180
- * An {@link AggregateMetadataKey} representing the max value of the field.
229
+ * A {@link MetadataKey} representing the max value of the field.
181
230
  *
182
231
  * @category validation
183
232
  * @experimental 21.0.0
184
233
  */
185
- declare const MAX: AggregateMetadataKey<number | undefined, number | undefined>;
234
+ declare const MAX: MetadataKey<Signal<number | undefined>, number | undefined, number | undefined>;
186
235
  /**
187
- * An {@link AggregateMetadataKey} representing the min length of the field.
236
+ * A {@link MetadataKey} representing the min length of the field.
188
237
  *
189
238
  * @category validation
190
239
  * @experimental 21.0.0
191
240
  */
192
- declare const MIN_LENGTH: AggregateMetadataKey<number | undefined, number | undefined>;
241
+ declare const MIN_LENGTH: MetadataKey<Signal<number | undefined>, number | undefined, number | undefined>;
193
242
  /**
194
- * An {@link AggregateMetadataKey} representing the max length of the field.
243
+ * A {@link MetadataKey} representing the max length of the field.
195
244
  *
196
245
  * @category validation
197
246
  * @experimental 21.0.0
198
247
  */
199
- declare const MAX_LENGTH: AggregateMetadataKey<number | undefined, number | undefined>;
248
+ declare const MAX_LENGTH: MetadataKey<Signal<number | undefined>, number | undefined, number | undefined>;
200
249
  /**
201
- * An {@link AggregateMetadataKey} representing the patterns the field must match.
250
+ * A {@link MetadataKey} representing the patterns the field must match.
202
251
  *
203
252
  * @category validation
204
253
  * @experimental 21.0.0
205
254
  */
206
- declare const PATTERN: AggregateMetadataKey<RegExp[], RegExp | undefined>;
255
+ declare const PATTERN: MetadataKey<Signal<RegExp[]>, RegExp | undefined, RegExp[]>;
207
256
 
208
257
  /**
209
- * Options used to create a `ValidationError`.
258
+ * Symbol used to retain generic type information when it would otherwise be lost.
210
259
  */
211
- interface ValidationErrorOptions {
212
- /** Human readable error message. */
213
- message?: string;
214
- }
260
+ declare const ɵɵTYPE: unique symbol;
215
261
  /**
216
- * A type that requires the given type `T` to have a `field` property.
217
- * @template T The type to add a `field` to.
262
+ * A type that represents either a single value of type `T` or a readonly array of `T`.
263
+ * @template T The type of the value(s).
218
264
  *
219
265
  * @experimental 21.0.0
220
266
  */
221
- type WithField<T> = T & {
222
- field: FieldTree<unknown>;
223
- };
267
+ type OneOrMany<T> = T | readonly T[];
224
268
  /**
225
- * A type that allows the given type `T` to optionally have a `field` property.
226
- * @template T The type to optionally add a `field` to.
269
+ * The kind of `FieldPath` (`Root`, `Child` of another `FieldPath`, or `Item` in a `FieldPath` array)
227
270
  *
228
271
  * @experimental 21.0.0
229
272
  */
230
- type WithOptionalField<T> = Omit<T, 'field'> & {
231
- field?: FieldTree<unknown>;
232
- };
273
+ type PathKind = PathKind.Root | PathKind.Child | PathKind.Item;
274
+ declare namespace PathKind {
275
+ /**
276
+ * The `PathKind` for a `FieldPath` that is at the root of its field tree.
277
+ */
278
+ interface Root {
279
+ /**
280
+ * The `ɵɵTYPE` is constructed to allow the `extends` clause on `Child` and `Item` to narrow the
281
+ * type. Another way to think about this is, if we have a function that expects this kind of
282
+ * path, the `ɵɵTYPE` lists the kinds of path we are allowed to pass to it.
283
+ */
284
+ [ɵɵTYPE]: 'root' | 'child' | 'item';
285
+ }
286
+ /**
287
+ * The `PathKind` for a `FieldPath` that is a child of another `FieldPath`.
288
+ */
289
+ interface Child extends PathKind.Root {
290
+ [ɵɵTYPE]: 'child' | 'item';
291
+ }
292
+ /**
293
+ * The `PathKind` for a `FieldPath` that is an item in a `FieldPath` array.
294
+ */
295
+ interface Item extends PathKind.Child {
296
+ [ɵɵTYPE]: 'item';
297
+ }
298
+ }
233
299
  /**
234
- * A type that ensures the given type `T` does not have a `field` property.
235
- * @template T The type to remove the `field` from.
300
+ * A status indicating whether a field is unsubmitted, submitted, or currently submitting.
236
301
  *
302
+ * @category types
237
303
  * @experimental 21.0.0
238
304
  */
239
- type WithoutField<T> = T & {
240
- field: never;
241
- };
305
+ type SubmittedStatus = 'unsubmitted' | 'submitted' | 'submitting';
242
306
  /**
243
- * Create a required error associated with the target field
244
- * @param options The validation error options
307
+ * A reason for a field's disablement.
245
308
  *
309
+ * @category logic
246
310
  * @experimental 21.0.0
247
311
  */
248
- declare function requiredError(options: WithField<ValidationErrorOptions>): RequiredValidationError;
312
+ interface DisabledReason {
313
+ /** The field that is disabled. */
314
+ readonly field: FieldTree<unknown>;
315
+ /** A user-facing message describing the reason for the disablement. */
316
+ readonly message?: string;
317
+ }
249
318
  /**
250
- * Create a required error
251
- * @param options The optional validation error options
319
+ * The absence of an error which indicates a successful validation result.
252
320
  *
253
- * @category validation
321
+ * @category types
254
322
  * @experimental 21.0.0
255
323
  */
256
- declare function requiredError(options?: ValidationErrorOptions): WithoutField<RequiredValidationError>;
324
+ type ValidationSuccess = null | undefined | void;
257
325
  /**
258
- * Create a min value error associated with the target field
259
- * @param min The min value constraint
260
- * @param options The validation error options
326
+ * The result of running a tree validation function.
261
327
  *
262
- * @category validation
263
- * @experimental 21.0.0
264
- */
265
- declare function minError(min: number, options: WithField<ValidationErrorOptions>): MinValidationError;
266
- /**
267
- * Create a min value error
268
- * @param min The min value constraint
269
- * @param options The optional validation error options
328
+ * The result may be one of the following:
329
+ * 1. A {@link ValidationSuccess} to indicate no errors.
330
+ * 2. A {@link ValidationError} without a field to indicate an error on the field being validated.
331
+ * 3. A {@link ValidationError} with a field to indicate an error on the target field.
332
+ * 4. A list of {@link ValidationError} with or without fields to indicate multiple errors.
270
333
  *
271
- * @category validation
272
- * @experimental 21.0.0
273
- */
274
- declare function minError(min: number, options?: ValidationErrorOptions): WithoutField<MinValidationError>;
275
- /**
276
- * Create a max value error associated with the target field
277
- * @param max The max value constraint
278
- * @param options The validation error options
334
+ * @template E the type of error (defaults to {@link ValidationError}).
279
335
  *
280
- * @category validation
336
+ * @category types
281
337
  * @experimental 21.0.0
282
338
  */
283
- declare function maxError(max: number, options: WithField<ValidationErrorOptions>): MaxValidationError;
339
+ type TreeValidationResult<E extends ValidationError.WithOptionalField = ValidationError.WithOptionalField> = ValidationSuccess | OneOrMany<E>;
284
340
  /**
285
- * Create a max value error
286
- * @param max The max value constraint
287
- * @param options The optional validation error options
341
+ * A validation result where all errors explicitly define their target field.
288
342
  *
289
- * @category validation
290
- * @experimental 21.0.0
291
- */
292
- declare function maxError(max: number, options?: ValidationErrorOptions): WithoutField<MaxValidationError>;
293
- /**
294
- * Create a minLength error associated with the target field
295
- * @param minLength The minLength constraint
296
- * @param options The validation error options
343
+ * The result may be one of the following:
344
+ * 1. A {@link ValidationSuccess} to indicate no errors.
345
+ * 2. A {@link ValidationError} with a field to indicate an error on the target field.
346
+ * 3. A list of {@link ValidationError} with fields to indicate multiple errors.
297
347
  *
298
- * @category validation
299
- * @experimental 21.0.0
300
- */
301
- declare function minLengthError(minLength: number, options: WithField<ValidationErrorOptions>): MinLengthValidationError;
302
- /**
303
- * Create a minLength error
304
- * @param minLength The minLength constraint
305
- * @param options The optional validation error options
348
+ * @template E the type of error (defaults to {@link ValidationError}).
306
349
  *
307
- * @category validation
350
+ * @category types
308
351
  * @experimental 21.0.0
309
352
  */
310
- declare function minLengthError(minLength: number, options?: ValidationErrorOptions): WithoutField<MinLengthValidationError>;
353
+ type ValidationResult<E extends ValidationError = ValidationError> = ValidationSuccess | OneOrMany<E>;
311
354
  /**
312
- * Create a maxLength error associated with the target field
313
- * @param maxLength The maxLength constraint
314
- * @param options The validation error options
355
+ * An asynchronous validation result where all errors explicitly define their target field.
315
356
  *
316
- * @category validation
317
- * @experimental 21.0.0
318
- */
319
- declare function maxLengthError(maxLength: number, options: WithField<ValidationErrorOptions>): MaxLengthValidationError;
320
- /**
321
- * Create a maxLength error
322
- * @param maxLength The maxLength constraint
323
- * @param options The optional validation error options
357
+ * The result may be one of the following:
358
+ * 1. A {@link ValidationResult} to indicate the result if resolved.
359
+ * 5. 'pending' if the validation is not yet resolved.
324
360
  *
325
- * @category validation
326
- * @experimental 21.0.0
327
- */
328
- declare function maxLengthError(maxLength: number, options?: ValidationErrorOptions): WithoutField<MaxLengthValidationError>;
329
- /**
330
- * Create a pattern matching error associated with the target field
331
- * @param pattern The violated pattern
332
- * @param options The validation error options
361
+ * @template E the type of error (defaults to {@link ValidationError}).
333
362
  *
334
- * @category validation
363
+ * @category types
335
364
  * @experimental 21.0.0
336
365
  */
337
- declare function patternError(pattern: RegExp, options: WithField<ValidationErrorOptions>): PatternValidationError;
366
+ type AsyncValidationResult<E extends ValidationError = ValidationError> = ValidationResult<E> | 'pending';
338
367
  /**
339
- * Create a pattern matching error
340
- * @param pattern The violated pattern
341
- * @param options The optional validation error options
368
+ * An object that represents a tree of fields in a form. This includes both primitive value fields
369
+ * (e.g. fields that contain a `string` or `number`), as well as "grouping fields" that contain
370
+ * sub-fields. `FieldTree` objects are arranged in a tree whose structure mimics the structure of the
371
+ * underlying data. For example a `FieldTree<{x: number}>` has a property `x` which contains a
372
+ * `FieldTree<number>`. To access the state associated with a field, call it as a function.
342
373
  *
343
- * @category validation
344
- * @experimental 21.0.0
345
- */
346
- declare function patternError(pattern: RegExp, options?: ValidationErrorOptions): WithoutField<PatternValidationError>;
347
- /**
348
- * Create an email format error associated with the target field
349
- * @param options The validation error options
374
+ * @template TValue The type of the data which the field is wrapped around.
375
+ * @template TKey The type of the property key which this field resides under in its parent.
350
376
  *
351
- * @category validation
377
+ * @category types
352
378
  * @experimental 21.0.0
353
379
  */
354
- declare function emailError(options: WithField<ValidationErrorOptions>): EmailValidationError;
380
+ type FieldTree<TModel, TKey extends string | number = string | number> = (() => [TModel] extends [AbstractControl] ? CompatFieldState<TModel, TKey> : FieldState<TModel, TKey>) & ([TModel] extends [AbstractControl] ? object : [TModel] extends [Array<infer U>] ? ReadonlyArrayLike<MaybeFieldTree<U, number>> : TModel extends Record<string, any> ? Subfields<TModel> : object);
355
381
  /**
356
- * Create an email format error
357
- * @param options The optional validation error options
382
+ * The sub-fields that a user can navigate to from a `FieldTree<TModel>`.
358
383
  *
359
- * @category validation
360
- * @experimental 21.0.0
361
- */
362
- declare function emailError(options?: ValidationErrorOptions): WithoutField<EmailValidationError>;
363
- /**
364
- * Create a standard schema issue error associated with the target field
365
- * @param issue The standard schema issue
366
- * @param options The validation error options
384
+ * @template TModel The type of the data which the parent field is wrapped around.
367
385
  *
368
- * @category validation
369
386
  * @experimental 21.0.0
370
387
  */
371
- declare function standardSchemaError(issue: StandardSchemaV1.Issue, options: WithField<ValidationErrorOptions>): StandardSchemaValidationError;
388
+ type Subfields<TModel> = {
389
+ readonly [K in keyof TModel as TModel[K] extends Function ? never : K]: MaybeFieldTree<TModel[K], string>;
390
+ } & {
391
+ [Symbol.iterator](): Iterator<[string, MaybeFieldTree<TModel[keyof TModel], string>]>;
392
+ };
372
393
  /**
373
- * Create a standard schema issue error
374
- * @param issue The standard schema issue
375
- * @param options The optional validation error options
394
+ * An iterable object with the same shape as a readonly array.
395
+ *
396
+ * @template T The array item type.
376
397
  *
377
- * @category validation
378
398
  * @experimental 21.0.0
379
399
  */
380
- declare function standardSchemaError(issue: StandardSchemaV1.Issue, options?: ValidationErrorOptions): WithoutField<StandardSchemaValidationError>;
400
+ type ReadonlyArrayLike<T> = Pick<ReadonlyArray<T>, number | 'length' | typeof Symbol.iterator>;
381
401
  /**
382
- * Create a custom error associated with the target field
383
- * @param obj The object to create an error from
402
+ * Helper type for defining `FieldTree`. Given a type `TValue` that may include `undefined`, it extracts
403
+ * the `undefined` outside the `FieldTree` type.
404
+ *
405
+ * For example `MaybeField<{a: number} | undefined, TKey>` would be equivalent to
406
+ * `undefined | FieldTree<{a: number}, TKey>`.
407
+ *
408
+ * @template TModel The type of the data which the field is wrapped around.
409
+ * @template TKey The type of the property key which this field resides under in its parent.
384
410
  *
385
- * @category validation
386
411
  * @experimental 21.0.0
387
412
  */
388
- declare function customError<E extends Partial<ValidationError.WithField>>(obj: WithField<E>): CustomValidationError;
413
+ type MaybeFieldTree<TModel, TKey extends string | number = string | number> = (TModel & undefined) | FieldTree<Exclude<TModel, undefined>, TKey>;
389
414
  /**
390
- * Create a custom error
391
- * @param obj The object to create an error from
415
+ * Contains all of the state (e.g. value, statuses, etc.) associated with a `FieldTree`, exposed as
416
+ * signals.
392
417
  *
393
- * @category validation
418
+ * @category structure
394
419
  * @experimental 21.0.0
395
420
  */
396
- declare function customError<E extends Partial<ValidationError.WithField>>(obj?: E): WithoutField<CustomValidationError>;
397
- /**
398
- * Common interface for all validation errors.
399
- *
400
- * This can be returned from validators.
401
- *
402
- * It's also used by the creation functions to create an instance
403
- * (e.g. `requiredError`, `minError`, etc.).
404
- *
405
- * @category validation
406
- * @experimental 21.0.0
407
- */
408
- interface ValidationError {
409
- /** Identifies the kind of error. */
410
- readonly kind: string;
411
- /** Human readable error message. */
412
- readonly message?: string;
413
- }
414
- declare namespace ValidationError {
421
+ interface FieldState<TValue, TKey extends string | number = string | number> extends _FieldState<TValue> {
415
422
  /**
416
- * Validation error with a field.
423
+ * A signal indicating whether field value has been changed by user.
424
+ */
425
+ readonly dirty: Signal<boolean>;
426
+ /**
427
+ * A signal indicating whether a field is hidden.
417
428
  *
418
- * This is returned from field state, e.g., catField.errors() would be of a list of errors with
419
- * `field: catField` bound to state.
429
+ * When a field is hidden it is ignored when determining the valid, touched, and dirty states.
430
+ *
431
+ * Note: This doesn't hide the field in the template, that must be done manually.
432
+ * ```
433
+ * @if (!field.hidden()) {
434
+ * ...
435
+ * }
436
+ * ```
420
437
  */
421
- interface WithField extends ValidationError {
422
- /** The field associated with this error. */
423
- readonly field: FieldTree<unknown>;
424
- }
438
+ readonly hidden: Signal<boolean>;
439
+ readonly disabledReasons: Signal<readonly DisabledReason[]>;
440
+ readonly errors: Signal<ValidationError.WithField[]>;
425
441
  /**
426
- * Validation error with optional field.
442
+ * A signal containing the {@link errors} of the field and its descendants.
443
+ */
444
+ readonly errorSummary: Signal<ValidationError.WithField[]>;
445
+ /**
446
+ * A signal indicating whether the field's value is currently valid.
427
447
  *
428
- * This is generally used in places where the result might have a field.
429
- * e.g., as a result of a `validateTree`, or when handling form submission.
448
+ * Note: `valid()` is not the same as `!invalid()`.
449
+ * - `valid()` is `true` when there are no validation errors *and* no pending validators.
450
+ * - `invalid()` is `true` when there are validation errors, regardless of pending validators.
451
+ *
452
+ * Ex: consider the situation where a field has 3 validators, 2 of which have no errors and 1 of
453
+ * which is still pending. In this case `valid()` is `false` because of the pending validator.
454
+ * However `invalid()` is also `false` because there are no errors.
430
455
  */
431
- interface WithOptionalField extends ValidationError {
432
- /** The field associated with this error. */
433
- readonly field?: FieldTree<unknown>;
434
- }
456
+ readonly valid: Signal<boolean>;
435
457
  /**
436
- * Validation error with no field.
458
+ * A signal indicating whether the field's value is currently invalid.
437
459
  *
438
- * This is used to strongly enforce that fields are not allowed in validation result.
460
+ * Note: `invalid()` is not the same as `!valid()`.
461
+ * - `invalid()` is `true` when there are validation errors, regardless of pending validators.
462
+ * - `valid()` is `true` when there are no validation errors *and* no pending validators.
463
+ *
464
+ * Ex: consider the situation where a field has 3 validators, 2 of which have no errors and 1 of
465
+ * which is still pending. In this case `invalid()` is `false` because there are no errors.
466
+ * However `valid()` is also `false` because of the pending validator.
439
467
  */
440
- interface WithoutField extends ValidationError {
441
- /** The field associated with this error. */
442
- readonly field?: never;
443
- }
468
+ readonly invalid: Signal<boolean>;
469
+ /**
470
+ * Whether there are any validators still pending for this field.
471
+ */
472
+ readonly pending: Signal<boolean>;
473
+ /**
474
+ * A signal indicating whether the field is currently in the process of being submitted.
475
+ */
476
+ readonly submitting: Signal<boolean>;
477
+ /**
478
+ * The property key in the parent field under which this field is stored. If the parent field is
479
+ * array-valued, for example, this is the index of this field in that array.
480
+ */
481
+ readonly keyInParent: Signal<TKey>;
482
+ /**
483
+ * The {@link Field} directives that bind this field to a UI control.
484
+ */
485
+ readonly fieldBindings: Signal<readonly Field<unknown>[]>;
486
+ /**
487
+ * Reads a metadata value from the field.
488
+ * @param key The metadata key to read.
489
+ */
490
+ metadata<M>(key: MetadataKey<M, any, any>): M | undefined;
491
+ /**
492
+ * Resets the {@link touched} and {@link dirty} state of the field and its descendants.
493
+ *
494
+ * Note this does not change the data model, which can be reset directly if desired.
495
+ *
496
+ * @param value Optional value to set to the form. If not passed, the value will not be changed.
497
+ */
498
+ reset(value?: TValue): void;
444
499
  }
445
500
  /**
446
- * A custom error that may contain additional properties
501
+ * This is FieldState also providing access to the wrapped FormControl.
447
502
  *
448
- * @category validation
503
+ * @category interop
449
504
  * @experimental 21.0.0
450
505
  */
451
- declare class CustomValidationError implements ValidationError {
452
- /** Brand the class to avoid Typescript structural matching */
453
- private __brand;
506
+ type CompatFieldState<TControl extends AbstractControl, TKey extends string | number = string | number> = FieldState<TControl extends AbstractControl<unknown, infer TValue> ? TValue : never, TKey> & {
507
+ control: Signal<TControl>;
508
+ };
509
+ /**
510
+ * Allows declaring whether the Rules are supported for a given path.
511
+ *
512
+ * @experimental 21.0.0
513
+ **/
514
+ type SchemaPathRules = SchemaPathRules.Supported | SchemaPathRules.Unsupported;
515
+ declare namespace SchemaPathRules {
454
516
  /**
455
- * Allow the user to attach arbitrary other properties.
517
+ * Used for paths that support settings rules.
456
518
  */
457
- [key: PropertyKey]: unknown;
458
- /** Identifies the kind of error. */
459
- readonly kind: string;
460
- /** The field associated with this error. */
461
- readonly field: FieldTree<unknown>;
462
- /** Human readable error message. */
463
- readonly message?: string;
464
- constructor(options?: ValidationErrorOptions);
519
+ type Supported = 1;
520
+ /**
521
+ * Used for paths that do not support settings rules, e.g., compatPath.
522
+ */
523
+ type Unsupported = 2;
465
524
  }
466
525
  /**
467
- * Internal version of `NgValidationError`, we create this separately so we can change its type on
468
- * the exported version to a type union of the possible sub-classes.
526
+ * An object that represents a location in the `FieldTree` tree structure and is used to bind logic to a
527
+ * particular part of the structure prior to the creation of the form. Because the `FieldPath`
528
+ * exists prior to the form's creation, it cannot be used to access any of the field state.
469
529
  *
530
+ * @template TValue The type of the data which the form is wrapped around.
531
+ * @template TPathKind The kind of path (root field, child field, or item of an array)
532
+ *
533
+ * @category types
470
534
  * @experimental 21.0.0
471
535
  */
472
- declare abstract class _NgValidationError implements ValidationError {
473
- /** Brand the class to avoid Typescript structural matching */
474
- private __brand;
475
- /** Identifies the kind of error. */
476
- readonly kind: string;
477
- /** The field associated with this error. */
478
- readonly field: FieldTree<unknown>;
479
- /** Human readable error message. */
480
- readonly message?: string;
481
- constructor(options?: ValidationErrorOptions);
482
- }
536
+ type SchemaPath<TValue, TSupportsRules extends SchemaPathRules = SchemaPathRules.Supported, TPathKind extends PathKind = PathKind.Root> = {
537
+ [ɵɵTYPE]: {
538
+ value: () => TValue;
539
+ supportsRules: TSupportsRules;
540
+ pathKind: TPathKind;
541
+ };
542
+ };
483
543
  /**
484
- * An error used to indicate that a required field is empty.
544
+ * Schema path used if the value is an AbstractControl.
485
545
  *
486
- * @category validation
546
+ * @category interop
487
547
  * @experimental 21.0.0
488
548
  */
489
- declare class RequiredValidationError extends _NgValidationError {
490
- readonly kind = "required";
491
- }
549
+ type CompatSchemaPath<TControl extends AbstractControl, TPathKind extends PathKind = PathKind.Root> = SchemaPath<TControl extends AbstractControl<unknown, infer TValue> ? TValue : never, SchemaPathRules.Unsupported, TPathKind> & {
550
+ [ɵɵTYPE]: {
551
+ control: TControl;
552
+ };
553
+ };
492
554
  /**
493
- * An error used to indicate that a value is lower than the minimum allowed.
555
+ * Nested schema path.
556
+ *
557
+ * It mirrors the structure of a given data structure, and allows applying rules to the appropriate
558
+ * fields.
494
559
  *
495
- * @category validation
496
560
  * @experimental 21.0.0
497
561
  */
498
- declare class MinValidationError extends _NgValidationError {
499
- readonly min: number;
500
- readonly kind = "min";
501
- constructor(min: number, options?: ValidationErrorOptions);
502
- }
562
+ type SchemaPathTree<TModel, TPathKind extends PathKind = PathKind.Root> = ([TModel] extends [AbstractControl] ? CompatSchemaPath<TModel, TPathKind> : SchemaPath<TModel, SchemaPathRules.Supported, TPathKind>) & (TModel extends AbstractControl ? unknown : TModel extends Array<any> ? unknown : TModel extends Record<string, any> ? {
563
+ [K in keyof TModel]: MaybeSchemaPathTree<TModel[K], PathKind.Child>;
564
+ } : unknown);
503
565
  /**
504
- * An error used to indicate that a value is higher than the maximum allowed.
566
+ * Helper type for defining `FieldPath`. Given a type `TValue` that may include `undefined`, it
567
+ * extracts the `undefined` outside the `FieldPath` type.
568
+ *
569
+ * For example `MaybeFieldPath<{a: number} | undefined, PathKind.Child>` would be equivalent to
570
+ * `undefined | FieldTree<{a: number}, PathKind.child>`.
571
+ *
572
+ * @template TValue The type of the data which the field is wrapped around.
573
+ * @template TPathKind The kind of path (root field, child field, or item of an array)
505
574
  *
506
- * @category validation
507
575
  * @experimental 21.0.0
508
576
  */
509
- declare class MaxValidationError extends _NgValidationError {
510
- readonly max: number;
511
- readonly kind = "max";
512
- constructor(max: number, options?: ValidationErrorOptions);
513
- }
577
+ type MaybeSchemaPathTree<TModel, TPathKind extends PathKind = PathKind.Root> = (TModel & undefined) | SchemaPathTree<Exclude<TModel, undefined>, TPathKind>;
514
578
  /**
515
- * An error used to indicate that a value is shorter than the minimum allowed length.
579
+ * Defines logic for a form.
516
580
  *
517
- * @category validation
581
+ * @template TValue The type of data stored in the form that this schema is attached to.
582
+ *
583
+ * @category types
518
584
  * @experimental 21.0.0
519
585
  */
520
- declare class MinLengthValidationError extends _NgValidationError {
521
- readonly minLength: number;
522
- readonly kind = "minLength";
523
- constructor(minLength: number, options?: ValidationErrorOptions);
524
- }
586
+ type Schema<in TModel> = {
587
+ [ɵɵTYPE]: SchemaFn<TModel, PathKind.Root>;
588
+ };
525
589
  /**
526
- * An error used to indicate that a value is longer than the maximum allowed length.
590
+ * Function that defines rules for a schema.
527
591
  *
528
- * @category validation
592
+ * @template TModel The type of data stored in the form that this schema function is attached to.
593
+ * @template TPathKind The kind of path this schema function can be bound to.
594
+ *
595
+ * @category types
529
596
  * @experimental 21.0.0
530
597
  */
531
- declare class MaxLengthValidationError extends _NgValidationError {
532
- readonly maxLength: number;
533
- readonly kind = "maxLength";
534
- constructor(maxLength: number, options?: ValidationErrorOptions);
535
- }
598
+ type SchemaFn<TModel, TPathKind extends PathKind = PathKind.Root> = (p: SchemaPathTree<TModel, TPathKind>) => void;
536
599
  /**
537
- * An error used to indicate that a value does not match the required pattern.
600
+ * A schema or schema definition function.
538
601
  *
539
- * @category validation
602
+ * @template TModel The type of data stored in the form that this schema function is attached to.
603
+ * @template TPathKind The kind of path this schema function can be bound to.
604
+ *
605
+ * @category types
540
606
  * @experimental 21.0.0
541
607
  */
542
- declare class PatternValidationError extends _NgValidationError {
543
- readonly pattern: RegExp;
544
- readonly kind = "pattern";
545
- constructor(pattern: RegExp, options?: ValidationErrorOptions);
546
- }
608
+ type SchemaOrSchemaFn<TModel, TPathKind extends PathKind = PathKind.Root> = Schema<TModel> | SchemaFn<TModel, TPathKind>;
547
609
  /**
548
- * An error used to indicate that a value is not a valid email.
610
+ * A function that receives the `FieldContext` for the field the logic is bound to and returns
611
+ * a specific result type.
549
612
  *
550
- * @category validation
613
+ * @template TValue The data type for the field the logic is bound to.
614
+ * @template TReturn The type of the result returned by the logic function.
615
+ * @template TPathKind The kind of path the logic is applied to (root field, child field, or item of an array)
616
+ *
617
+ * @category types
551
618
  * @experimental 21.0.0
552
619
  */
553
- declare class EmailValidationError extends _NgValidationError {
554
- readonly kind = "email";
555
- }
620
+ type LogicFn<TValue, TReturn, TPathKind extends PathKind = PathKind.Root> = (ctx: FieldContext<TValue, TPathKind>) => TReturn;
556
621
  /**
557
- * An error used to indicate an issue validating against a standard schema.
622
+ * A function that takes the `FieldContext` for the field being validated and returns a
623
+ * `ValidationResult` indicating errors for the field.
624
+ *
625
+ * @template TValue The type of value stored in the field being validated
626
+ * @template TPathKind The kind of path being validated (root field, child field, or item of an array)
558
627
  *
559
628
  * @category validation
560
629
  * @experimental 21.0.0
561
630
  */
562
- declare class StandardSchemaValidationError extends _NgValidationError {
563
- readonly issue: StandardSchemaV1.Issue;
564
- readonly kind = "standardSchema";
565
- constructor(issue: StandardSchemaV1.Issue, options?: ValidationErrorOptions);
566
- }
631
+ type FieldValidator<TValue, TPathKind extends PathKind = PathKind.Root> = LogicFn<TValue, ValidationResult<ValidationError.WithoutField>, TPathKind>;
567
632
  /**
568
- * The base class for all built-in, non-custom errors. This class can be used to check if an error
569
- * is one of the standard kinds, allowing you to switch on the kind to further narrow the type.
633
+ * A function that takes the `FieldContext` for the field being validated and returns a
634
+ * `TreeValidationResult` indicating errors for the field and its sub-fields.
570
635
  *
571
- * @example
572
- * ```
573
- * const f = form(...);
574
- * for (const e of form().errors()) {
575
- * if (e instanceof NgValidationError) {
576
- * switch(e.kind) {
577
- * case 'required':
578
- * console.log('This is required!');
579
- * break;
580
- * case 'min':
581
- * console.log(`Must be at least ${e.min}`);
582
- * break;
583
- * ...
584
- * }
585
- * }
586
- * }
587
- * ```
636
+ * @template TValue The type of value stored in the field being validated
637
+ * @template TPathKind The kind of path being validated (root field, child field, or item of an array)
588
638
  *
589
- * @category validation
639
+ * @category types
590
640
  * @experimental 21.0.0
591
641
  */
592
- declare const NgValidationError: abstract new () => NgValidationError;
593
- type NgValidationError = RequiredValidationError | MinValidationError | MaxValidationError | MinLengthValidationError | MaxLengthValidationError | PatternValidationError | EmailValidationError | StandardSchemaValidationError;
594
-
642
+ type TreeValidator<TValue, TPathKind extends PathKind = PathKind.Root> = LogicFn<TValue, TreeValidationResult, TPathKind>;
595
643
  /**
596
- * Symbol used to retain generic type information when it would otherwise be lost.
644
+ * A function that takes the `FieldContext` for the field being validated and returns a
645
+ * `ValidationResult` indicating errors for the field and its sub-fields. In a `Validator` all
646
+ * errors must explicitly define their target field.
647
+ *
648
+ * @template TValue The type of value stored in the field being validated
649
+ * @template TPathKind The kind of path being validated (root field, child field, or item of an array)
650
+ *
651
+ * @category types
652
+ * @experimental 21.0.0
597
653
  */
598
- declare const ɵɵTYPE: unique symbol;
654
+ type Validator<TValue, TPathKind extends PathKind = PathKind.Root> = LogicFn<TValue, ValidationResult, TPathKind>;
599
655
  /**
600
- * A type that represents either a single value of type `T` or a readonly array of `T`.
601
- * @template T The type of the value(s).
656
+ * Provides access to the state of the current field as well as functions that can be used to look
657
+ * up state of other fields based on a `FieldPath`.
602
658
  *
659
+ * @category types
603
660
  * @experimental 21.0.0
604
661
  */
605
- type OneOrMany<T> = T | readonly T[];
662
+ type FieldContext<TValue, TPathKind extends PathKind = PathKind.Root> = TPathKind extends PathKind.Item ? ItemFieldContext<TValue> : TPathKind extends PathKind.Child ? ChildFieldContext<TValue> : RootFieldContext<TValue>;
606
663
  /**
607
- * The kind of `FieldPath` (`Root`, `Child` of another `FieldPath`, or `Item` in a `FieldPath` array)
664
+ * The base field context that is available for all fields.
608
665
  *
609
666
  * @experimental 21.0.0
610
667
  */
611
- type PathKind = PathKind.Root | PathKind.Child | PathKind.Item;
612
- declare namespace PathKind {
613
- /**
614
- * The `PathKind` for a `FieldPath` that is at the root of its field tree.
615
- */
616
- interface Root {
617
- /**
618
- * The `ɵɵTYPE` is constructed to allow the `extends` clause on `Child` and `Item` to narrow the
619
- * type. Another way to think about this is, if we have a function that expects this kind of
620
- * path, the `ɵɵTYPE` lists the kinds of path we are allowed to pass to it.
621
- */
622
- [ɵɵTYPE]: 'root' | 'child' | 'item';
623
- }
624
- /**
625
- * The `PathKind` for a `FieldPath` that is a child of another `FieldPath`.
626
- */
627
- interface Child extends PathKind.Root {
628
- [ɵɵTYPE]: 'child' | 'item';
629
- }
630
- /**
631
- * The `PathKind` for a `FieldPath` that is an item in a `FieldPath` array.
632
- */
633
- interface Item extends PathKind.Child {
634
- [ɵɵTYPE]: 'item';
635
- }
668
+ interface RootFieldContext<TValue> {
669
+ /** A signal containing the value of the current field. */
670
+ readonly value: Signal<TValue>;
671
+ /** The state of the current field. */
672
+ readonly state: FieldState<TValue>;
673
+ /** The current field. */
674
+ readonly field: FieldTree<TValue>;
675
+ /** Gets the value of the field represented by the given path. */
676
+ valueOf<PValue>(p: SchemaPath<PValue, SchemaPathRules>): PValue;
677
+ /** Gets the state of the field represented by the given path. */
678
+ stateOf<PControl extends AbstractControl>(p: CompatSchemaPath<PControl>): CompatFieldState<PControl>;
679
+ stateOf<PValue>(p: SchemaPath<PValue, SchemaPathRules>): FieldState<PValue>;
680
+ /** Gets the field represented by the given path. */
681
+ fieldTreeOf<PModel>(p: SchemaPathTree<PModel>): FieldTree<PModel>;
682
+ /** The list of keys that lead from the root field to the current field. */
683
+ readonly pathKeys: Signal<readonly string[]>;
636
684
  }
637
685
  /**
638
- * A status indicating whether a field is unsubmitted, submitted, or currently submitting.
686
+ * Field context that is available for all fields that are a child of another field.
639
687
  *
640
- * @category types
688
+ * @category structure
641
689
  * @experimental 21.0.0
642
690
  */
643
- type SubmittedStatus = 'unsubmitted' | 'submitted' | 'submitting';
691
+ interface ChildFieldContext<TValue> extends RootFieldContext<TValue> {
692
+ /** The key of the current field in its parent field. */
693
+ readonly key: Signal<string>;
694
+ }
644
695
  /**
645
- * A reason for a field's disablement.
696
+ * Field context that is available for all fields that are an item in an array field.
646
697
  *
647
- * @category logic
648
698
  * @experimental 21.0.0
649
699
  */
650
- interface DisabledReason {
651
- /** The field that is disabled. */
652
- readonly field: FieldTree<unknown>;
653
- /** A user-facing message describing the reason for the disablement. */
654
- readonly message?: string;
700
+ interface ItemFieldContext<TValue> extends ChildFieldContext<TValue> {
701
+ /** The index of the current field in its parent field. */
702
+ readonly index: Signal<number>;
655
703
  }
656
704
  /**
657
- * The absence of an error which indicates a successful validation result.
705
+ * Gets the item type of an object that is possibly an array.
658
706
  *
659
- * @category types
660
707
  * @experimental 21.0.0
661
708
  */
662
- type ValidationSuccess = null | undefined | void;
709
+ type ItemType<T extends Object> = T extends ReadonlyArray<any> ? T[number] : T[keyof T];
663
710
  /**
664
- * The result of running a tree validation function.
711
+ * A function that defines custom debounce logic for a field.
665
712
  *
666
- * The result may be one of the following:
667
- * 1. A {@link ValidationSuccess} to indicate no errors.
668
- * 2. A {@link ValidationError} without a field to indicate an error on the field being validated.
669
- * 3. A {@link ValidationError} with a field to indicate an error on the target field.
670
- * 4. A list of {@link ValidationError} with or without fields to indicate multiple errors.
713
+ * @param context The field context.
714
+ * @param abortSignal An `AbortSignal` used to communicate that the debounced operation was aborted.
715
+ * @returns A `Promise<void>` to debounce an update, or `void` to apply an update immediately.
716
+ * @template TValue The type of value stored in the field.
717
+ * @template TPathKind The kind of path the debouncer is applied to (root field, child field, or item of an array).
671
718
  *
672
- * @template E the type of error (defaults to {@link ValidationError}).
719
+ * @experimental 21.0.0
720
+ */
721
+ type Debouncer<TValue, TPathKind extends PathKind = PathKind.Root> = (context: FieldContext<TValue, TPathKind>, abortSignal: AbortSignal) => Promise<void> | void;
722
+
723
+ /**
724
+ * Options used to create a `ValidationError`.
725
+ */
726
+ interface ValidationErrorOptions {
727
+ /** Human readable error message. */
728
+ message?: string;
729
+ }
730
+ /**
731
+ * A type that requires the given type `T` to have a `field` property.
732
+ * @template T The type to add a `field` to.
673
733
  *
674
- * @category types
675
734
  * @experimental 21.0.0
676
735
  */
677
- type TreeValidationResult<E extends ValidationError.WithOptionalField = ValidationError.WithOptionalField> = ValidationSuccess | OneOrMany<E>;
736
+ type WithField<T> = T & {
737
+ field: FieldTree<unknown>;
738
+ };
678
739
  /**
679
- * A validation result where all errors explicitly define their target field.
740
+ * A type that allows the given type `T` to optionally have a `field` property.
741
+ * @template T The type to optionally add a `field` to.
680
742
  *
681
- * The result may be one of the following:
682
- * 1. A {@link ValidationSuccess} to indicate no errors.
683
- * 2. A {@link ValidationError} with a field to indicate an error on the target field.
684
- * 3. A list of {@link ValidationError} with fields to indicate multiple errors.
743
+ * @experimental 21.0.0
744
+ */
745
+ type WithOptionalField<T> = Omit<T, 'field'> & {
746
+ field?: FieldTree<unknown>;
747
+ };
748
+ /**
749
+ * A type that ensures the given type `T` does not have a `field` property.
750
+ * @template T The type to remove the `field` from.
685
751
  *
686
- * @template E the type of error (defaults to {@link ValidationError}).
752
+ * @experimental 21.0.0
753
+ */
754
+ type WithoutField<T> = T & {
755
+ field: never;
756
+ };
757
+ /**
758
+ * Create a required error associated with the target field
759
+ * @param options The validation error options
687
760
  *
688
- * @category types
689
761
  * @experimental 21.0.0
690
762
  */
691
- type ValidationResult<E extends ValidationError = ValidationError> = ValidationSuccess | OneOrMany<E>;
763
+ declare function requiredError(options: WithField<ValidationErrorOptions>): RequiredValidationError;
692
764
  /**
693
- * An asynchronous validation result where all errors explicitly define their target field.
765
+ * Create a required error
766
+ * @param options The optional validation error options
694
767
  *
695
- * The result may be one of the following:
696
- * 1. A {@link ValidationResult} to indicate the result if resolved.
697
- * 5. 'pending' if the validation is not yet resolved.
768
+ * @category validation
769
+ * @experimental 21.0.0
770
+ */
771
+ declare function requiredError(options?: ValidationErrorOptions): WithoutField<RequiredValidationError>;
772
+ /**
773
+ * Create a min value error associated with the target field
774
+ * @param min The min value constraint
775
+ * @param options The validation error options
698
776
  *
699
- * @template E the type of error (defaults to {@link ValidationError}).
777
+ * @category validation
778
+ * @experimental 21.0.0
779
+ */
780
+ declare function minError(min: number, options: WithField<ValidationErrorOptions>): MinValidationError;
781
+ /**
782
+ * Create a min value error
783
+ * @param min The min value constraint
784
+ * @param options The optional validation error options
785
+ *
786
+ * @category validation
787
+ * @experimental 21.0.0
788
+ */
789
+ declare function minError(min: number, options?: ValidationErrorOptions): WithoutField<MinValidationError>;
790
+ /**
791
+ * Create a max value error associated with the target field
792
+ * @param max The max value constraint
793
+ * @param options The validation error options
794
+ *
795
+ * @category validation
796
+ * @experimental 21.0.0
797
+ */
798
+ declare function maxError(max: number, options: WithField<ValidationErrorOptions>): MaxValidationError;
799
+ /**
800
+ * Create a max value error
801
+ * @param max The max value constraint
802
+ * @param options The optional validation error options
700
803
  *
701
- * @category types
804
+ * @category validation
702
805
  * @experimental 21.0.0
703
806
  */
704
- type AsyncValidationResult<E extends ValidationError = ValidationError> = ValidationResult<E> | 'pending';
807
+ declare function maxError(max: number, options?: ValidationErrorOptions): WithoutField<MaxValidationError>;
705
808
  /**
706
- * An object that represents a tree of fields in a form. This includes both primitive value fields
707
- * (e.g. fields that contain a `string` or `number`), as well as "grouping fields" that contain
708
- * sub-fields. `FieldTree` objects are arranged in a tree whose structure mimics the structure of the
709
- * underlying data. For example a `FieldTree<{x: number}>` has a property `x` which contains a
710
- * `FieldTree<number>`. To access the state associated with a field, call it as a function.
711
- *
712
- * @template TValue The type of the data which the field is wrapped around.
713
- * @template TKey The type of the property key which this field resides under in its parent.
809
+ * Create a minLength error associated with the target field
810
+ * @param minLength The minLength constraint
811
+ * @param options The validation error options
714
812
  *
715
- * @category types
813
+ * @category validation
716
814
  * @experimental 21.0.0
717
815
  */
718
- type FieldTree<TModel, TKey extends string | number = string | number> = (() => [TModel] extends [AbstractControl] ? CompatFieldState<TModel, TKey> : FieldState<TModel, TKey>) & ([TModel] extends [AbstractControl] ? object : [TModel] extends [Array<infer U>] ? ReadonlyArrayLike<MaybeFieldTree<U, number>> : TModel extends Record<string, any> ? Subfields<TModel> : object);
816
+ declare function minLengthError(minLength: number, options: WithField<ValidationErrorOptions>): MinLengthValidationError;
719
817
  /**
720
- * The sub-fields that a user can navigate to from a `FieldTree<TModel>`.
721
- *
722
- * @template TModel The type of the data which the parent field is wrapped around.
818
+ * Create a minLength error
819
+ * @param minLength The minLength constraint
820
+ * @param options The optional validation error options
723
821
  *
822
+ * @category validation
724
823
  * @experimental 21.0.0
725
824
  */
726
- type Subfields<TModel> = {
727
- readonly [K in keyof TModel as TModel[K] extends Function ? never : K]: MaybeFieldTree<TModel[K], string>;
728
- } & {
729
- [Symbol.iterator](): Iterator<[string, MaybeFieldTree<TModel[keyof TModel], string>]>;
730
- };
825
+ declare function minLengthError(minLength: number, options?: ValidationErrorOptions): WithoutField<MinLengthValidationError>;
731
826
  /**
732
- * An iterable object with the same shape as a readonly array.
733
- *
734
- * @template T The array item type.
827
+ * Create a maxLength error associated with the target field
828
+ * @param maxLength The maxLength constraint
829
+ * @param options The validation error options
735
830
  *
831
+ * @category validation
736
832
  * @experimental 21.0.0
737
833
  */
738
- type ReadonlyArrayLike<T> = Pick<ReadonlyArray<T>, number | 'length' | typeof Symbol.iterator>;
834
+ declare function maxLengthError(maxLength: number, options: WithField<ValidationErrorOptions>): MaxLengthValidationError;
739
835
  /**
740
- * Helper type for defining `FieldTree`. Given a type `TValue` that may include `undefined`, it extracts
741
- * the `undefined` outside the `FieldTree` type.
742
- *
743
- * For example `MaybeField<{a: number} | undefined, TKey>` would be equivalent to
744
- * `undefined | FieldTree<{a: number}, TKey>`.
745
- *
746
- * @template TModel The type of the data which the field is wrapped around.
747
- * @template TKey The type of the property key which this field resides under in its parent.
836
+ * Create a maxLength error
837
+ * @param maxLength The maxLength constraint
838
+ * @param options The optional validation error options
748
839
  *
840
+ * @category validation
749
841
  * @experimental 21.0.0
750
842
  */
751
- type MaybeFieldTree<TModel, TKey extends string | number = string | number> = (TModel & undefined) | FieldTree<Exclude<TModel, undefined>, TKey>;
843
+ declare function maxLengthError(maxLength: number, options?: ValidationErrorOptions): WithoutField<MaxLengthValidationError>;
752
844
  /**
753
- * Contains all of the state (e.g. value, statuses, etc.) associated with a `FieldTree`, exposed as
754
- * signals.
845
+ * Create a pattern matching error associated with the target field
846
+ * @param pattern The violated pattern
847
+ * @param options The validation error options
755
848
  *
756
- * @category structure
849
+ * @category validation
757
850
  * @experimental 21.0.0
758
851
  */
759
- interface FieldState<TValue, TKey extends string | number = string | number> extends _FieldState<TValue> {
760
- /**
761
- * A signal indicating whether field value has been changed by user.
762
- */
763
- readonly dirty: Signal<boolean>;
764
- /**
765
- * A signal indicating whether a field is hidden.
766
- *
767
- * When a field is hidden it is ignored when determining the valid, touched, and dirty states.
768
- *
769
- * Note: This doesn't hide the field in the template, that must be done manually.
770
- * ```
771
- * @if (!field.hidden()) {
772
- * ...
773
- * }
774
- * ```
775
- */
776
- readonly hidden: Signal<boolean>;
777
- readonly disabledReasons: Signal<readonly DisabledReason[]>;
778
- readonly errors: Signal<ValidationError.WithField[]>;
779
- /**
780
- * A signal containing the {@link errors} of the field and its descendants.
781
- */
782
- readonly errorSummary: Signal<ValidationError.WithField[]>;
783
- /**
784
- * A signal indicating whether the field's value is currently valid.
785
- *
786
- * Note: `valid()` is not the same as `!invalid()`.
787
- * - `valid()` is `true` when there are no validation errors *and* no pending validators.
788
- * - `invalid()` is `true` when there are validation errors, regardless of pending validators.
789
- *
790
- * Ex: consider the situation where a field has 3 validators, 2 of which have no errors and 1 of
791
- * which is still pending. In this case `valid()` is `false` because of the pending validator.
792
- * However `invalid()` is also `false` because there are no errors.
793
- */
794
- readonly valid: Signal<boolean>;
795
- /**
796
- * A signal indicating whether the field's value is currently invalid.
797
- *
798
- * Note: `invalid()` is not the same as `!valid()`.
799
- * - `invalid()` is `true` when there are validation errors, regardless of pending validators.
800
- * - `valid()` is `true` when there are no validation errors *and* no pending validators.
801
- *
802
- * Ex: consider the situation where a field has 3 validators, 2 of which have no errors and 1 of
803
- * which is still pending. In this case `invalid()` is `false` because there are no errors.
804
- * However `valid()` is also `false` because of the pending validator.
805
- */
806
- readonly invalid: Signal<boolean>;
807
- /**
808
- * Whether there are any validators still pending for this field.
809
- */
810
- readonly pending: Signal<boolean>;
811
- /**
812
- * A signal indicating whether the field is currently in the process of being submitted.
813
- */
814
- readonly submitting: Signal<boolean>;
815
- /**
816
- * The property key in the parent field under which this field is stored. If the parent field is
817
- * array-valued, for example, this is the index of this field in that array.
818
- */
819
- readonly keyInParent: Signal<TKey>;
820
- /**
821
- * The {@link Field} directives that bind this field to a UI control.
822
- */
823
- readonly fieldBindings: Signal<readonly Field<unknown>[]>;
824
- /**
825
- * Reads an aggregate metadata value from the field.
826
- * @param key The metadata key to read.
827
- */
828
- metadata<M>(key: AggregateMetadataKey<M, any>): Signal<M>;
829
- /**
830
- * Reads a metadata value from the field.
831
- * @param key The metadata key to read.
832
- */
833
- metadata<M>(key: MetadataKey<M>): M | undefined;
834
- /**
835
- * Checks whether the given metadata key has been defined for this field.
836
- */
837
- hasMetadata(key: MetadataKey<any> | AggregateMetadataKey<any, any>): boolean;
838
- /**
839
- * Resets the {@link touched} and {@link dirty} state of the field and its descendants.
840
- *
841
- * Note this does not change the data model, which can be reset directly if desired.
842
- *
843
- * @param value Optional value to set to the form. If not passed, the value will not be changed.
844
- */
845
- reset(value?: TValue): void;
846
- }
852
+ declare function patternError(pattern: RegExp, options: WithField<ValidationErrorOptions>): PatternValidationError;
847
853
  /**
848
- * This is FieldState also providing access to the wrapped FormControl.
854
+ * Create a pattern matching error
855
+ * @param pattern The violated pattern
856
+ * @param options The optional validation error options
849
857
  *
850
- * @category interop
858
+ * @category validation
851
859
  * @experimental 21.0.0
852
860
  */
853
- type CompatFieldState<TControl extends AbstractControl, TKey extends string | number = string | number> = FieldState<TControl extends AbstractControl<unknown, infer TValue> ? TValue : never, TKey> & {
854
- control: Signal<TControl>;
855
- };
861
+ declare function patternError(pattern: RegExp, options?: ValidationErrorOptions): WithoutField<PatternValidationError>;
856
862
  /**
857
- * Allows declaring whether the Rules are supported for a given path.
863
+ * Create an email format error associated with the target field
864
+ * @param options The validation error options
858
865
  *
866
+ * @category validation
859
867
  * @experimental 21.0.0
860
- **/
861
- type SchemaPathRules = SchemaPathRules.Supported | SchemaPathRules.Unsupported;
862
- declare namespace SchemaPathRules {
863
- /**
864
- * Used for paths that support settings rules.
865
- */
866
- type Supported = 1;
867
- /**
868
- * Used for paths that do not support settings rules, e.g., compatPath.
869
- */
870
- type Unsupported = 2;
871
- }
868
+ */
869
+ declare function emailError(options: WithField<ValidationErrorOptions>): EmailValidationError;
872
870
  /**
873
- * An object that represents a location in the `FieldTree` tree structure and is used to bind logic to a
874
- * particular part of the structure prior to the creation of the form. Because the `FieldPath`
875
- * exists prior to the form's creation, it cannot be used to access any of the field state.
876
- *
877
- * @template TValue The type of the data which the form is wrapped around.
878
- * @template TPathKind The kind of path (root field, child field, or item of an array)
871
+ * Create an email format error
872
+ * @param options The optional validation error options
879
873
  *
880
- * @category types
874
+ * @category validation
881
875
  * @experimental 21.0.0
882
876
  */
883
- type SchemaPath<TValue, TSupportsRules extends SchemaPathRules = SchemaPathRules.Supported, TPathKind extends PathKind = PathKind.Root> = {
884
- [ɵɵTYPE]: {
885
- value: () => TValue;
886
- supportsRules: TSupportsRules;
887
- pathKind: TPathKind;
888
- };
889
- };
877
+ declare function emailError(options?: ValidationErrorOptions): WithoutField<EmailValidationError>;
890
878
  /**
891
- * Schema path used if the value is an AbstractControl.
879
+ * Create a standard schema issue error associated with the target field
880
+ * @param issue The standard schema issue
881
+ * @param options The validation error options
892
882
  *
893
- * @category interop
883
+ * @category validation
894
884
  * @experimental 21.0.0
895
885
  */
896
- type CompatSchemaPath<TControl extends AbstractControl, TPathKind extends PathKind = PathKind.Root> = SchemaPath<TControl extends AbstractControl<unknown, infer TValue> ? TValue : never, SchemaPathRules.Unsupported, TPathKind> & {
897
- [ɵɵTYPE]: {
898
- control: TControl;
899
- };
900
- };
886
+ declare function standardSchemaError(issue: StandardSchemaV1.Issue, options: WithField<ValidationErrorOptions>): StandardSchemaValidationError;
901
887
  /**
902
- * Nested schema path.
903
- *
904
- * It mirrors the structure of a given data structure, and allows applying rules to the appropriate
905
- * fields.
888
+ * Create a standard schema issue error
889
+ * @param issue The standard schema issue
890
+ * @param options The optional validation error options
906
891
  *
892
+ * @category validation
907
893
  * @experimental 21.0.0
908
894
  */
909
- type SchemaPathTree<TModel, TPathKind extends PathKind = PathKind.Root> = ([TModel] extends [AbstractControl] ? CompatSchemaPath<TModel, TPathKind> : SchemaPath<TModel, SchemaPathRules.Supported, TPathKind>) & (TModel extends AbstractControl ? unknown : TModel extends Array<any> ? unknown : TModel extends Record<string, any> ? {
910
- [K in keyof TModel]: MaybeSchemaPathTree<TModel[K], PathKind.Child>;
911
- } : unknown);
895
+ declare function standardSchemaError(issue: StandardSchemaV1.Issue, options?: ValidationErrorOptions): WithoutField<StandardSchemaValidationError>;
912
896
  /**
913
- * Helper type for defining `FieldPath`. Given a type `TValue` that may include `undefined`, it
914
- * extracts the `undefined` outside the `FieldPath` type.
915
- *
916
- * For example `MaybeFieldPath<{a: number} | undefined, PathKind.Child>` would be equivalent to
917
- * `undefined | FieldTree<{a: number}, PathKind.child>`.
918
- *
919
- * @template TValue The type of the data which the field is wrapped around.
920
- * @template TPathKind The kind of path (root field, child field, or item of an array)
897
+ * Create a custom error associated with the target field
898
+ * @param obj The object to create an error from
921
899
  *
900
+ * @category validation
922
901
  * @experimental 21.0.0
923
902
  */
924
- type MaybeSchemaPathTree<TModel, TPathKind extends PathKind = PathKind.Root> = (TModel & undefined) | SchemaPathTree<Exclude<TModel, undefined>, TPathKind>;
903
+ declare function customError<E extends Partial<ValidationError.WithField>>(obj: WithField<E>): CustomValidationError;
925
904
  /**
926
- * Defines logic for a form.
927
- *
928
- * @template TValue The type of data stored in the form that this schema is attached to.
905
+ * Create a custom error
906
+ * @param obj The object to create an error from
929
907
  *
930
- * @category types
908
+ * @category validation
931
909
  * @experimental 21.0.0
932
910
  */
933
- type Schema<in TModel> = {
934
- [ɵɵTYPE]: SchemaFn<TModel, PathKind.Root>;
935
- };
911
+ declare function customError<E extends Partial<ValidationError.WithField>>(obj?: E): WithoutField<CustomValidationError>;
936
912
  /**
937
- * Function that defines rules for a schema.
913
+ * Common interface for all validation errors.
938
914
  *
939
- * @template TModel The type of data stored in the form that this schema function is attached to.
940
- * @template TPathKind The kind of path this schema function can be bound to.
915
+ * This can be returned from validators.
941
916
  *
942
- * @category types
917
+ * It's also used by the creation functions to create an instance
918
+ * (e.g. `requiredError`, `minError`, etc.).
919
+ *
920
+ * @category validation
943
921
  * @experimental 21.0.0
944
922
  */
945
- type SchemaFn<TModel, TPathKind extends PathKind = PathKind.Root> = (p: SchemaPathTree<TModel, TPathKind>) => void;
923
+ interface ValidationError {
924
+ /** Identifies the kind of error. */
925
+ readonly kind: string;
926
+ /** Human readable error message. */
927
+ readonly message?: string;
928
+ }
929
+ declare namespace ValidationError {
930
+ /**
931
+ * Validation error with a field.
932
+ *
933
+ * This is returned from field state, e.g., catField.errors() would be of a list of errors with
934
+ * `field: catField` bound to state.
935
+ */
936
+ interface WithField extends ValidationError {
937
+ /** The field associated with this error. */
938
+ readonly field: FieldTree<unknown>;
939
+ }
940
+ /**
941
+ * Validation error with optional field.
942
+ *
943
+ * This is generally used in places where the result might have a field.
944
+ * e.g., as a result of a `validateTree`, or when handling form submission.
945
+ */
946
+ interface WithOptionalField extends ValidationError {
947
+ /** The field associated with this error. */
948
+ readonly field?: FieldTree<unknown>;
949
+ }
950
+ /**
951
+ * Validation error with no field.
952
+ *
953
+ * This is used to strongly enforce that fields are not allowed in validation result.
954
+ */
955
+ interface WithoutField extends ValidationError {
956
+ /** The field associated with this error. */
957
+ readonly field?: never;
958
+ }
959
+ }
946
960
  /**
947
- * A schema or schema definition function.
948
- *
949
- * @template TModel The type of data stored in the form that this schema function is attached to.
950
- * @template TPathKind The kind of path this schema function can be bound to.
961
+ * A custom error that may contain additional properties
951
962
  *
952
- * @category types
963
+ * @category validation
953
964
  * @experimental 21.0.0
954
965
  */
955
- type SchemaOrSchemaFn<TModel, TPathKind extends PathKind = PathKind.Root> = Schema<TModel> | SchemaFn<TModel, TPathKind>;
966
+ declare class CustomValidationError implements ValidationError {
967
+ /** Brand the class to avoid Typescript structural matching */
968
+ private __brand;
969
+ /**
970
+ * Allow the user to attach arbitrary other properties.
971
+ */
972
+ [key: PropertyKey]: unknown;
973
+ /** Identifies the kind of error. */
974
+ readonly kind: string;
975
+ /** The field associated with this error. */
976
+ readonly field: FieldTree<unknown>;
977
+ /** Human readable error message. */
978
+ readonly message?: string;
979
+ constructor(options?: ValidationErrorOptions);
980
+ }
956
981
  /**
957
- * A function that receives the `FieldContext` for the field the logic is bound to and returns
958
- * a specific result type.
959
- *
960
- * @template TValue The data type for the field the logic is bound to.
961
- * @template TReturn The type of the result returned by the logic function.
962
- * @template TPathKind The kind of path the logic is applied to (root field, child field, or item of an array)
982
+ * Internal version of `NgValidationError`, we create this separately so we can change its type on
983
+ * the exported version to a type union of the possible sub-classes.
963
984
  *
964
- * @category types
965
985
  * @experimental 21.0.0
966
986
  */
967
- type LogicFn<TValue, TReturn, TPathKind extends PathKind = PathKind.Root> = (ctx: FieldContext<TValue, TPathKind>) => TReturn;
987
+ declare abstract class _NgValidationError implements ValidationError {
988
+ /** Brand the class to avoid Typescript structural matching */
989
+ private __brand;
990
+ /** Identifies the kind of error. */
991
+ readonly kind: string;
992
+ /** The field associated with this error. */
993
+ readonly field: FieldTree<unknown>;
994
+ /** Human readable error message. */
995
+ readonly message?: string;
996
+ constructor(options?: ValidationErrorOptions);
997
+ }
968
998
  /**
969
- * A function that takes the `FieldContext` for the field being validated and returns a
970
- * `ValidationResult` indicating errors for the field.
971
- *
972
- * @template TValue The type of value stored in the field being validated
973
- * @template TPathKind The kind of path being validated (root field, child field, or item of an array)
999
+ * An error used to indicate that a required field is empty.
974
1000
  *
975
1001
  * @category validation
976
1002
  * @experimental 21.0.0
977
1003
  */
978
- type FieldValidator<TValue, TPathKind extends PathKind = PathKind.Root> = LogicFn<TValue, ValidationResult<ValidationError.WithoutField>, TPathKind>;
1004
+ declare class RequiredValidationError extends _NgValidationError {
1005
+ readonly kind = "required";
1006
+ }
979
1007
  /**
980
- * A function that takes the `FieldContext` for the field being validated and returns a
981
- * `TreeValidationResult` indicating errors for the field and its sub-fields.
982
- *
983
- * @template TValue The type of value stored in the field being validated
984
- * @template TPathKind The kind of path being validated (root field, child field, or item of an array)
1008
+ * An error used to indicate that a value is lower than the minimum allowed.
985
1009
  *
986
- * @category types
1010
+ * @category validation
987
1011
  * @experimental 21.0.0
988
1012
  */
989
- type TreeValidator<TValue, TPathKind extends PathKind = PathKind.Root> = LogicFn<TValue, TreeValidationResult, TPathKind>;
1013
+ declare class MinValidationError extends _NgValidationError {
1014
+ readonly min: number;
1015
+ readonly kind = "min";
1016
+ constructor(min: number, options?: ValidationErrorOptions);
1017
+ }
990
1018
  /**
991
- * A function that takes the `FieldContext` for the field being validated and returns a
992
- * `ValidationResult` indicating errors for the field and its sub-fields. In a `Validator` all
993
- * errors must explicitly define their target field.
994
- *
995
- * @template TValue The type of value stored in the field being validated
996
- * @template TPathKind The kind of path being validated (root field, child field, or item of an array)
1019
+ * An error used to indicate that a value is higher than the maximum allowed.
997
1020
  *
998
- * @category types
1021
+ * @category validation
999
1022
  * @experimental 21.0.0
1000
1023
  */
1001
- type Validator<TValue, TPathKind extends PathKind = PathKind.Root> = LogicFn<TValue, ValidationResult, TPathKind>;
1024
+ declare class MaxValidationError extends _NgValidationError {
1025
+ readonly max: number;
1026
+ readonly kind = "max";
1027
+ constructor(max: number, options?: ValidationErrorOptions);
1028
+ }
1002
1029
  /**
1003
- * Provides access to the state of the current field as well as functions that can be used to look
1004
- * up state of other fields based on a `FieldPath`.
1030
+ * An error used to indicate that a value is shorter than the minimum allowed length.
1005
1031
  *
1006
- * @category types
1032
+ * @category validation
1007
1033
  * @experimental 21.0.0
1008
1034
  */
1009
- type FieldContext<TValue, TPathKind extends PathKind = PathKind.Root> = TPathKind extends PathKind.Item ? ItemFieldContext<TValue> : TPathKind extends PathKind.Child ? ChildFieldContext<TValue> : RootFieldContext<TValue>;
1035
+ declare class MinLengthValidationError extends _NgValidationError {
1036
+ readonly minLength: number;
1037
+ readonly kind = "minLength";
1038
+ constructor(minLength: number, options?: ValidationErrorOptions);
1039
+ }
1010
1040
  /**
1011
- * The base field context that is available for all fields.
1041
+ * An error used to indicate that a value is longer than the maximum allowed length.
1012
1042
  *
1043
+ * @category validation
1013
1044
  * @experimental 21.0.0
1014
1045
  */
1015
- interface RootFieldContext<TValue> {
1016
- /** A signal containing the value of the current field. */
1017
- readonly value: Signal<TValue>;
1018
- /** The state of the current field. */
1019
- readonly state: FieldState<TValue>;
1020
- /** The current field. */
1021
- readonly field: FieldTree<TValue>;
1022
- /** Gets the value of the field represented by the given path. */
1023
- valueOf<PValue>(p: SchemaPath<PValue, SchemaPathRules>): PValue;
1024
- /** Gets the state of the field represented by the given path. */
1025
- stateOf<PControl extends AbstractControl>(p: CompatSchemaPath<PControl>): CompatFieldState<PControl>;
1026
- stateOf<PValue>(p: SchemaPath<PValue, SchemaPathRules>): FieldState<PValue>;
1027
- /** Gets the field represented by the given path. */
1028
- fieldTreeOf<PModel>(p: SchemaPathTree<PModel>): FieldTree<PModel>;
1029
- /** The list of keys that lead from the root field to the current field. */
1030
- readonly pathKeys: Signal<readonly string[]>;
1046
+ declare class MaxLengthValidationError extends _NgValidationError {
1047
+ readonly maxLength: number;
1048
+ readonly kind = "maxLength";
1049
+ constructor(maxLength: number, options?: ValidationErrorOptions);
1031
1050
  }
1032
1051
  /**
1033
- * Field context that is available for all fields that are a child of another field.
1052
+ * An error used to indicate that a value does not match the required pattern.
1034
1053
  *
1035
- * @category structure
1054
+ * @category validation
1036
1055
  * @experimental 21.0.0
1037
1056
  */
1038
- interface ChildFieldContext<TValue> extends RootFieldContext<TValue> {
1039
- /** The key of the current field in its parent field. */
1040
- readonly key: Signal<string>;
1057
+ declare class PatternValidationError extends _NgValidationError {
1058
+ readonly pattern: RegExp;
1059
+ readonly kind = "pattern";
1060
+ constructor(pattern: RegExp, options?: ValidationErrorOptions);
1041
1061
  }
1042
1062
  /**
1043
- * Field context that is available for all fields that are an item in an array field.
1063
+ * An error used to indicate that a value is not a valid email.
1044
1064
  *
1065
+ * @category validation
1045
1066
  * @experimental 21.0.0
1046
1067
  */
1047
- interface ItemFieldContext<TValue> extends ChildFieldContext<TValue> {
1048
- /** The index of the current field in its parent field. */
1049
- readonly index: Signal<number>;
1068
+ declare class EmailValidationError extends _NgValidationError {
1069
+ readonly kind = "email";
1050
1070
  }
1051
1071
  /**
1052
- * Gets the item type of an object that is possibly an array.
1072
+ * An error used to indicate an issue validating against a standard schema.
1053
1073
  *
1074
+ * @category validation
1054
1075
  * @experimental 21.0.0
1055
1076
  */
1056
- type ItemType<T extends Object> = T extends ReadonlyArray<any> ? T[number] : T[keyof T];
1077
+ declare class StandardSchemaValidationError extends _NgValidationError {
1078
+ readonly issue: StandardSchemaV1.Issue;
1079
+ readonly kind = "standardSchema";
1080
+ constructor(issue: StandardSchemaV1.Issue, options?: ValidationErrorOptions);
1081
+ }
1057
1082
  /**
1058
- * A function that defines custom debounce logic for a field.
1083
+ * The base class for all built-in, non-custom errors. This class can be used to check if an error
1084
+ * is one of the standard kinds, allowing you to switch on the kind to further narrow the type.
1059
1085
  *
1060
- * @param context The field context.
1061
- * @param abortSignal An `AbortSignal` used to communicate that the debounced operation was aborted.
1062
- * @returns A `Promise<void>` to debounce an update, or `void` to apply an update immediately.
1063
- * @template TValue The type of value stored in the field.
1064
- * @template TPathKind The kind of path the debouncer is applied to (root field, child field, or item of an array).
1086
+ * @example
1087
+ * ```ts
1088
+ * const f = form(...);
1089
+ * for (const e of form().errors()) {
1090
+ * if (e instanceof NgValidationError) {
1091
+ * switch(e.kind) {
1092
+ * case 'required':
1093
+ * console.log('This is required!');
1094
+ * break;
1095
+ * case 'min':
1096
+ * console.log(`Must be at least ${e.min}`);
1097
+ * break;
1098
+ * ...
1099
+ * }
1100
+ * }
1101
+ * }
1102
+ * ```
1065
1103
  *
1104
+ * @category validation
1066
1105
  * @experimental 21.0.0
1067
1106
  */
1068
- type Debouncer<TValue, TPathKind extends PathKind = PathKind.Root> = (context: FieldContext<TValue, TPathKind>, abortSignal: AbortSignal) => Promise<void> | void;
1107
+ declare const NgValidationError: abstract new () => NgValidationError;
1108
+ type NgValidationError = RequiredValidationError | MinValidationError | MaxValidationError | MinLengthValidationError | MaxLengthValidationError | PatternValidationError | EmailValidationError | StandardSchemaValidationError;
1069
1109
 
1070
1110
  /**
1071
1111
  * Configuration options for signal forms.
@@ -1202,41 +1242,27 @@ declare class LogicContainer {
1202
1242
  readonly syncTreeErrors: ArrayMergeIgnoreLogic<ValidationError.WithField, null>;
1203
1243
  /** Logic that produces asynchronous validation results (errors or 'pending'). */
1204
1244
  readonly asyncErrors: ArrayMergeIgnoreLogic<ValidationError.WithField | 'pending', null>;
1205
- /** A map of aggregate metadata keys to the `AbstractLogic` instances that compute their values. */
1206
- private readonly aggregateMetadataKeys;
1207
- /** A map of metadata keys to the factory functions that create their values. */
1208
- private readonly metadataFactories;
1245
+ /** A map of metadata keys to the `AbstractLogic` instances that compute their values. */
1246
+ private readonly metadata;
1209
1247
  /**
1210
1248
  * Constructs a new `Logic` container.
1211
1249
  * @param predicates An array of predicates that must all be true for the logic
1212
1250
  * functions within this container to be active.
1213
1251
  */
1214
1252
  constructor(predicates: ReadonlyArray<BoundPredicate>);
1215
- /** Checks whether there is logic for the given aggregate metadata key. */
1216
- hasAggregateMetadata(key: AggregateMetadataKey<any, any>): boolean;
1217
- /**
1218
- * Gets an iterable of [aggregate metadata, logic function] pairs.
1219
- * @returns An iterable of aggregate metadata entries.
1220
- */
1221
- getAggregateMetadataEntries(): MapIterator<[AggregateMetadataKey<unknown, unknown>, AbstractLogic<unknown, unknown>]>;
1253
+ /** Checks whether there is logic for the given metadata key. */
1254
+ hasMetadata(key: MetadataKey<any, any, any>): boolean;
1222
1255
  /**
1223
- * Gets an iterable of [metadata, value factory function] pairs.
1224
- * @returns An iterable of metadata factory entries.
1256
+ * Gets an iterable of [metadata key, logic function] pairs.
1257
+ * @returns An iterable of metadata keys.
1225
1258
  */
1226
- getMetadataFactoryEntries(): MapIterator<[MetadataKey<unknown>, (ctx: FieldContext<unknown>) => unknown]>;
1259
+ getMetadataKeys(): MapIterator<MetadataKey<unknown, unknown, unknown>>;
1227
1260
  /**
1228
- * Retrieves or creates the `AbstractLogic` for a given aggregate metadata key.
1229
- * @param key The `AggregateMetadataKey` for which to get the logic.
1261
+ * Retrieves or creates the `AbstractLogic` for a given metadata key.
1262
+ * @param key The `MetadataKey` for which to get the logic.
1230
1263
  * @returns The `AbstractLogic` associated with the key.
1231
1264
  */
1232
- getAggregateMetadata<T>(key: AggregateMetadataKey<any, T>): AbstractLogic<T>;
1233
- /**
1234
- * Adds a factory function for a given metadata key.
1235
- * @param key The `MetadataKey` to associate the factory with.
1236
- * @param factory The factory function.
1237
- * @throws If a factory is already defined for the given key.
1238
- */
1239
- addMetadataFactory(key: MetadataKey<unknown>, factory: (ctx: FieldContext<unknown>) => unknown): void;
1265
+ getMetadata<T>(key: MetadataKey<any, T, any>): AbstractLogic<T>;
1240
1266
  /**
1241
1267
  * Merges logic from another `Logic` instance into this one.
1242
1268
  * @param other The `Logic` instance to merge from.
@@ -1268,10 +1294,8 @@ declare abstract class AbstractLogicNodeBuilder {
1268
1294
  abstract addSyncTreeErrorRule(logic: LogicFn<any, ValidationResult>): void;
1269
1295
  /** Adds a rule for asynchronous validation errors for a field. */
1270
1296
  abstract addAsyncErrorRule(logic: LogicFn<any, AsyncValidationResult>): void;
1271
- /** Adds a rule to compute aggregate metadata for a field. */
1272
- abstract addAggregateMetadataRule<M>(key: AggregateMetadataKey<unknown, M>, logic: LogicFn<any, M>): void;
1273
- /** Adds a factory function to produce a data value associated with a field. */
1274
- abstract addMetadataFactory<D>(key: MetadataKey<D>, factory: (ctx: FieldContext<any>) => D): void;
1297
+ /** Adds a rule to compute metadata for a field. */
1298
+ abstract addMetadataRule<M>(key: MetadataKey<unknown, M, unknown>, logic: LogicFn<any, M>): void;
1275
1299
  /**
1276
1300
  * Gets a builder for a child node associated with the given property key.
1277
1301
  * @param key The property key of the child.
@@ -1317,8 +1341,7 @@ declare class LogicNodeBuilder extends AbstractLogicNodeBuilder {
1317
1341
  addSyncErrorRule(logic: LogicFn<any, ValidationResult<ValidationError.WithField>>): void;
1318
1342
  addSyncTreeErrorRule(logic: LogicFn<any, ValidationResult<ValidationError.WithField>>): void;
1319
1343
  addAsyncErrorRule(logic: LogicFn<any, AsyncValidationResult<ValidationError.WithField>>): void;
1320
- addAggregateMetadataRule<T>(key: AggregateMetadataKey<any, T>, logic: LogicFn<any, T>): void;
1321
- addMetadataFactory<D>(key: MetadataKey<D>, factory: (ctx: FieldContext<any>) => D): void;
1344
+ addMetadataRule<T>(key: MetadataKey<unknown, T, any>, logic: LogicFn<any, T>): void;
1322
1345
  getChild(key: PropertyKey): LogicNodeBuilder;
1323
1346
  hasLogic(builder: AbstractLogicNodeBuilder): boolean;
1324
1347
  /**
@@ -1447,13 +1470,13 @@ declare class FieldPathNode {
1447
1470
  */
1448
1471
  declare class FieldMetadataState {
1449
1472
  private readonly node;
1450
- /** A map of all `MetadataKey` and `AggregateMetadataKey` that have been defined for this field. */
1473
+ /** A map of all `MetadataKey` that have been defined for this field. */
1451
1474
  private readonly metadata;
1452
1475
  constructor(node: FieldNode);
1453
- /** Gets the value of a `MetadataKey` or `AggregateMetadataKey` for the field. */
1454
- get<T>(key: MetadataKey<T> | AggregateMetadataKey<T, unknown>): T | undefined | Signal<T>;
1476
+ /** Gets the value of an `MetadataKey` for the field. */
1477
+ get<T>(key: MetadataKey<T, unknown, unknown>): T | undefined;
1455
1478
  /** Checks whether the current metadata state has the given metadata key. */
1456
- has(key: MetadataKey<any> | AggregateMetadataKey<any, any>): boolean;
1479
+ has(key: MetadataKey<any, any, any>): boolean;
1457
1480
  }
1458
1481
 
1459
1482
  /**
@@ -1692,6 +1715,7 @@ declare class FieldNode implements FieldState<unknown> {
1692
1715
  * Proxy to this node which allows navigation of the form graph below it.
1693
1716
  */
1694
1717
  readonly fieldProxy: FieldTree<any>;
1718
+ private readonly pathNode;
1695
1719
  constructor(options: FieldNodeOptions);
1696
1720
  /**
1697
1721
  * The `AbortController` for the currently debounced sync, or `undefined` if there is none.
@@ -1720,16 +1744,14 @@ declare class FieldNode implements FieldState<unknown> {
1720
1744
  get fieldBindings(): Signal<readonly Field<unknown>[]>;
1721
1745
  get submitting(): Signal<boolean>;
1722
1746
  get name(): Signal<string>;
1723
- private metadataOrUndefined;
1724
1747
  get max(): Signal<number | undefined> | undefined;
1725
1748
  get maxLength(): Signal<number | undefined> | undefined;
1726
1749
  get min(): Signal<number | undefined> | undefined;
1727
1750
  get minLength(): Signal<number | undefined> | undefined;
1728
1751
  get pattern(): Signal<readonly RegExp[]>;
1729
1752
  get required(): Signal<boolean>;
1730
- metadata<M>(key: AggregateMetadataKey<M, any>): Signal<M>;
1731
- metadata<M>(key: MetadataKey<M>): M | undefined;
1732
- hasMetadata(key: MetadataKey<any> | AggregateMetadataKey<any, any>): boolean;
1753
+ metadata<M>(key: MetadataKey<M, any, any>): M | undefined;
1754
+ hasMetadata(key: MetadataKey<any, any, any>): boolean;
1733
1755
  /**
1734
1756
  * Marks this specific field as touched.
1735
1757
  */
@@ -1769,11 +1791,8 @@ declare class FieldNode implements FieldState<unknown> {
1769
1791
  * Creates a new root field node for a new form.
1770
1792
  */
1771
1793
  static newRoot<T>(fieldManager: FormFieldManager, value: WritableSignal<T>, pathNode: FieldPathNode, adapter: FieldAdapter): FieldNode;
1772
- /**
1773
- * Creates a child field node based on the given options.
1774
- */
1775
- private static newChild;
1776
1794
  createStructure(options: FieldNodeOptions): RootFieldNodeStructure | ChildFieldNodeStructure;
1795
+ private newChild;
1777
1796
  }
1778
1797
  /**
1779
1798
  * Field node of a field that has children.
@@ -1795,12 +1814,16 @@ interface ParentFieldNode extends FieldNode {
1795
1814
  type TrackingKey = PropertyKey & {
1796
1815
  __brand: 'FieldIdentity';
1797
1816
  };
1817
+ type ChildNodeCtor = (key: string, trackingKey: TrackingKey | undefined, isArray: boolean) => FieldNode;
1798
1818
  /** Structural component of a `FieldNode` which tracks its path, parent, and children. */
1799
1819
  declare abstract class FieldNodeStructure {
1800
- /** The logic to apply to this field. */
1801
- readonly logic: LogicNode;
1802
- /** Computed map of child fields, based on the current value of this field. */
1803
- abstract readonly childrenMap: Signal<Map<TrackingKey, FieldNode> | undefined>;
1820
+ /**
1821
+ * Computed map of child fields, based on the current value of this field.
1822
+ *
1823
+ * This structure reacts to `this.value` and produces a new `ChildrenData` when the
1824
+ * value changes structurally (fields added/removed/moved).
1825
+ */
1826
+ protected abstract readonly childrenMap: Signal<ChildrenData | undefined>;
1804
1827
  /** The field's value. */
1805
1828
  abstract readonly value: WritableSignal<unknown>;
1806
1829
  /**
@@ -1816,33 +1839,60 @@ declare abstract class FieldNodeStructure {
1816
1839
  abstract readonly pathKeys: Signal<readonly string[]>;
1817
1840
  /** The parent field of this field. */
1818
1841
  abstract readonly parent: FieldNode | undefined;
1842
+ readonly logic: LogicNode;
1843
+ readonly node: FieldNode;
1844
+ readonly createChildNode: ChildNodeCtor;
1819
1845
  /** Added to array elements for tracking purposes. */
1820
1846
  readonly identitySymbol: symbol;
1821
1847
  /** Lazily initialized injector. Do not access directly, access via `injector` getter instead. */
1822
1848
  private _injector;
1823
1849
  /** Lazily initialized injector. */
1824
1850
  get injector(): DestroyableInjector;
1825
- constructor(
1826
- /** The logic to apply to this field. */
1827
- logic: LogicNode);
1851
+ constructor(logic: LogicNode, node: FieldNode, createChildNode: ChildNodeCtor);
1828
1852
  /** Gets the child fields of this field. */
1829
1853
  children(): Iterable<FieldNode>;
1830
1854
  /** Retrieve a child `FieldNode` of this node by property key. */
1831
1855
  getChild(key: PropertyKey): FieldNode | undefined;
1856
+ /**
1857
+ * Perform a reduction over a field's children (if any) and return the result.
1858
+ *
1859
+ * Optionally, the reduction is short circuited based on the provided `shortCircuit` function.
1860
+ */
1861
+ reduceChildren<T>(initialValue: T, fn: (child: FieldNode, value: T) => T, shortCircuit?: (value: T) => boolean): T;
1832
1862
  /** Destroys the field when it is no longer needed. */
1833
1863
  destroy(): void;
1864
+ /**
1865
+ * Creates a keyInParent signal for a field node.
1866
+ *
1867
+ * For root nodes, returns ROOT_KEY_IN_PARENT which throws when accessed.
1868
+ * For child nodes, creates a computed that tracks the field's current key in its parent,
1869
+ * with special handling for tracked array elements.
1870
+ *
1871
+ * @param options The field node options
1872
+ * @param identityInParent The tracking identity (only for tracked array children)
1873
+ * @param initialKeyInParent The initial key in parent (only for child nodes)
1874
+ * @returns A signal representing the field's key in its parent
1875
+ */
1876
+ protected createKeyInParent(options: FieldNodeOptions, identityInParent: TrackingKey | undefined, initialKeyInParent: string | undefined): Signal<string>;
1877
+ protected createChildrenMap(): Signal<ChildrenData | undefined>;
1878
+ /**
1879
+ * Creates a "reader" computed for the given key.
1880
+ *
1881
+ * A reader is a computed signal that memoizes the access of the `FieldNode` stored at this key
1882
+ * (or returns `undefined` if no such field exists). Accessing fields via the reader ensures that
1883
+ * reactive consumers aren't notified unless the field at a key actually changes.
1884
+ */
1885
+ private createReader;
1834
1886
  }
1835
1887
  /** The structural component of a `FieldNode` that is the root of its field tree. */
1836
1888
  declare class RootFieldNodeStructure extends FieldNodeStructure {
1837
- /** The full field node that corresponds to this structure. */
1838
- private readonly node;
1839
1889
  readonly fieldManager: FormFieldManager;
1840
1890
  readonly value: WritableSignal<unknown>;
1841
1891
  get parent(): undefined;
1842
1892
  get root(): FieldNode;
1843
1893
  get pathKeys(): Signal<readonly string[]>;
1844
1894
  get keyInParent(): Signal<string>;
1845
- readonly childrenMap: Signal<Map<TrackingKey, FieldNode> | undefined>;
1895
+ protected readonly childrenMap: Signal<ChildrenData | undefined>;
1846
1896
  /**
1847
1897
  * Creates the structure for the root node of a field tree.
1848
1898
  *
@@ -1856,16 +1906,17 @@ declare class RootFieldNodeStructure extends FieldNodeStructure {
1856
1906
  */
1857
1907
  constructor(
1858
1908
  /** The full field node that corresponds to this structure. */
1859
- node: FieldNode, pathNode: FieldPathNode, logic: LogicNode, fieldManager: FormFieldManager, value: WritableSignal<unknown>, adapter: FieldAdapter, createChildNode: (options: ChildFieldNodeOptions) => FieldNode);
1909
+ node: FieldNode, logic: LogicNode, fieldManager: FormFieldManager, value: WritableSignal<unknown>, createChildNode: ChildNodeCtor);
1860
1910
  }
1861
1911
  /** The structural component of a child `FieldNode` within a field tree. */
1862
1912
  declare class ChildFieldNodeStructure extends FieldNodeStructure {
1913
+ readonly logic: LogicNode;
1863
1914
  readonly parent: ParentFieldNode;
1864
1915
  readonly root: FieldNode;
1865
1916
  readonly pathKeys: Signal<readonly string[]>;
1866
1917
  readonly keyInParent: Signal<string>;
1867
1918
  readonly value: WritableSignal<unknown>;
1868
- readonly childrenMap: Signal<Map<TrackingKey, FieldNode> | undefined>;
1919
+ readonly childrenMap: Signal<ChildrenData | undefined>;
1869
1920
  get fieldManager(): FormFieldManager;
1870
1921
  /**
1871
1922
  * Creates the structure for a child field node in a field tree.
@@ -1879,7 +1930,7 @@ declare class ChildFieldNodeStructure extends FieldNodeStructure {
1879
1930
  * @param adapter Adapter that knows how to create new fields and appropriate state.
1880
1931
  * @param createChildNode A factory function to create child nodes for this field.
1881
1932
  */
1882
- constructor(node: FieldNode, pathNode: FieldPathNode, logic: LogicNode, parent: ParentFieldNode, identityInParent: TrackingKey | undefined, initialKeyInParent: string, adapter: FieldAdapter, createChildNode: (options: ChildFieldNodeOptions) => FieldNode);
1933
+ constructor(node: FieldNode, logic: LogicNode, parent: ParentFieldNode, identityInParent: TrackingKey | undefined, initialKeyInParent: string, createChildNode: ChildNodeCtor);
1883
1934
  }
1884
1935
  /** Options passed when constructing a root field node. */
1885
1936
  interface RootFieldNodeOptions {
@@ -1915,6 +1966,38 @@ interface ChildFieldNodeOptions {
1915
1966
  }
1916
1967
  /** Options passed when constructing a field node. */
1917
1968
  type FieldNodeOptions = RootFieldNodeOptions | ChildFieldNodeOptions;
1969
+ /**
1970
+ * Derived data regarding child fields for a specific parent field.
1971
+ */
1972
+ interface ChildrenData {
1973
+ /**
1974
+ * Tracks `ChildData` for each property key within the parent.
1975
+ */
1976
+ readonly byPropertyKey: ReadonlyMap<string, ChildData>;
1977
+ /**
1978
+ * Tracks the instance of child `FieldNode`s by their tracking key, which is always 1:1 with the
1979
+ * fields, even if they move around in the parent.
1980
+ */
1981
+ readonly byTrackingKey?: ReadonlyMap<TrackingKey, FieldNode>;
1982
+ }
1983
+ /**
1984
+ * Data for a specific child within a parent.
1985
+ */
1986
+ interface ChildData {
1987
+ /**
1988
+ * A computed signal to access the `FieldNode` currently stored at a specific key.
1989
+ *
1990
+ * Because this is a computed, it only updates whenever the `FieldNode` at that key changes.
1991
+ * Because `ChildData` is always associated with a specific key via `ChildrenData.byPropertyKey`,
1992
+ * this computed gives a stable way to watch the field stored for a given property and only
1993
+ * receives notifications when that field changes.
1994
+ */
1995
+ readonly reader: Signal<FieldNode | undefined>;
1996
+ /**
1997
+ * The child `FieldNode` currently stored at this key.
1998
+ */
1999
+ node: FieldNode;
2000
+ }
1918
2001
 
1919
2002
  /**
1920
2003
  * Manages the collection of fields associated with a given `form`.
@@ -2022,7 +2105,7 @@ interface FormOptions {
2022
2105
  * as well.
2023
2106
  *
2024
2107
  * @example
2025
- * ```
2108
+ * ```ts
2026
2109
  * const nameModel = signal({first: '', last: ''});
2027
2110
  * const nameForm = form(nameModel);
2028
2111
  * nameForm.first().value.set('John');
@@ -2049,7 +2132,7 @@ declare function form<TModel>(model: WritableSignal<TModel>): FieldTree<TModel>;
2049
2132
  * as well.
2050
2133
  *
2051
2134
  * @example
2052
- * ```
2135
+ * ```ts
2053
2136
  * const nameModel = signal({first: '', last: ''});
2054
2137
  * const nameForm = form(nameModel);
2055
2138
  * nameForm.first().value.set('John');
@@ -2062,7 +2145,7 @@ declare function form<TModel>(model: WritableSignal<TModel>): FieldTree<TModel>;
2062
2145
  * function that builds the schema by binding logic to a parts of the field structure.
2063
2146
  *
2064
2147
  * @example
2065
- * ```
2148
+ * ```ts
2066
2149
  * const nameForm = form(signal({first: '', last: ''}), (name) => {
2067
2150
  * required(name.first);
2068
2151
  * pattern(name.last, /^[a-z]+$/i, {message: 'Alphabet characters only'});
@@ -2095,7 +2178,7 @@ declare function form<TModel>(model: WritableSignal<TModel>, schemaOrOptions: Sc
2095
2178
  * as well.
2096
2179
  *
2097
2180
  * @example
2098
- * ```
2181
+ * ```ts
2099
2182
  * const nameModel = signal({first: '', last: ''});
2100
2183
  * const nameForm = form(nameModel);
2101
2184
  * nameForm.first().value.set('John');
@@ -2108,7 +2191,7 @@ declare function form<TModel>(model: WritableSignal<TModel>, schemaOrOptions: Sc
2108
2191
  * function that builds the schema by binding logic to a parts of the field structure.
2109
2192
  *
2110
2193
  * @example
2111
- * ```
2194
+ * ```ts
2112
2195
  * const nameForm = form(signal({first: '', last: ''}), (name) => {
2113
2196
  * required(name.first);
2114
2197
  * validate(name.last, ({value}) => !/^[a-z]+$/i.test(value()) ? customError({kind: 'alphabet-only'}) : undefined);
@@ -2134,7 +2217,7 @@ declare function form<TModel>(model: WritableSignal<TModel>, schema: SchemaOrSch
2134
2217
  * Applies a schema to each item of an array.
2135
2218
  *
2136
2219
  * @example
2137
- * ```
2220
+ * ```ts
2138
2221
  * const nameSchema = schema<{first: string, last: string}>((name) => {
2139
2222
  * required(name.first);
2140
2223
  * required(name.last);
@@ -2158,7 +2241,7 @@ declare function applyEach<TValue extends Object>(path: SchemaPath<TValue>, sche
2158
2241
  * Applies a predefined schema to a given `FieldPath`.
2159
2242
  *
2160
2243
  * @example
2161
- * ```
2244
+ * ```ts
2162
2245
  * const nameSchema = schema<{first: string, last: string}>((name) => {
2163
2246
  * required(name.first);
2164
2247
  * required(name.last);
@@ -2222,7 +2305,7 @@ declare function applyWhenValue<TValue>(path: SchemaPath<TValue>, predicate: (va
2222
2305
  * server error.
2223
2306
  *
2224
2307
  * @example
2225
- * ```
2308
+ * ```ts
2226
2309
  * async function registerNewUser(registrationForm: FieldTree<{username: string, password: string}>) {
2227
2310
  * const result = await myClient.registerNewUser(registrationForm().value());
2228
2311
  * if (result.errorCode === myClient.ErrorCode.USERNAME_TAKEN) {
@@ -2261,5 +2344,5 @@ declare function submit<TModel>(form: FieldTree<TModel>, action: (form: FieldTre
2261
2344
  */
2262
2345
  declare function schema<TValue>(fn: SchemaFn<TValue>): Schema<TValue>;
2263
2346
 
2264
- export { AggregateMetadataKey, CustomValidationError, EmailValidationError, FIELD, Field, MAX, MAX_LENGTH, MIN, MIN_LENGTH, MaxLengthValidationError, MaxValidationError, MetadataKey, MinLengthValidationError, MinValidationError, NgValidationError, PATTERN, PathKind, PatternValidationError, REQUIRED, RequiredValidationError, SchemaPathRules, StandardSchemaValidationError, ValidationError, andMetadataKey, apply, applyEach, applyWhen, applyWhenValue, createMetadataKey, customError, emailError, form, listMetadataKey, maxError, maxLengthError, maxMetadataKey, minError, minLengthError, minMetadataKey, orMetadataKey, patternError, provideSignalFormsConfig, reducedMetadataKey, requiredError, schema, standardSchemaError, submit };
2265
- export type { AsyncValidationResult, ChildFieldContext, CompatFieldState, CompatSchemaPath, Debouncer, DisabledReason, FieldContext, FieldState, FieldTree, FieldValidator, FormOptions, ItemFieldContext, ItemType, LogicFn, MaybeFieldTree, MaybeSchemaPathTree, OneOrMany, ReadonlyArrayLike, RootFieldContext, Schema, SchemaFn, SchemaOrSchemaFn, SchemaPath, SchemaPathTree, SignalFormsConfig, Subfields, SubmittedStatus, TreeValidationResult, TreeValidator, ValidationResult, ValidationSuccess, Validator, WithField, WithOptionalField, WithoutField };
2347
+ export { CustomValidationError, EmailValidationError, FIELD, Field, MAX, MAX_LENGTH, MIN, MIN_LENGTH, MaxLengthValidationError, MaxValidationError, MetadataKey, MetadataReducer, MinLengthValidationError, MinValidationError, NgValidationError, PATTERN, PathKind, PatternValidationError, REQUIRED, RequiredValidationError, SchemaPathRules, StandardSchemaValidationError, ValidationError, apply, applyEach, applyWhen, applyWhenValue, createManagedMetadataKey, createMetadataKey, customError, emailError, form, maxError, maxLengthError, metadata, minError, minLengthError, patternError, provideSignalFormsConfig, requiredError, schema, standardSchemaError, submit };
2348
+ export type { AsyncValidationResult, ChildFieldContext, CompatFieldState, CompatSchemaPath, Debouncer, DisabledReason, FieldContext, FieldState, FieldTree, FieldValidator, FormOptions, ItemFieldContext, ItemType, LogicFn, MaybeFieldTree, MaybeSchemaPathTree, MetadataSetterType, OneOrMany, ReadonlyArrayLike, RootFieldContext, Schema, SchemaFn, SchemaOrSchemaFn, SchemaPath, SchemaPathTree, SignalFormsConfig, Subfields, SubmittedStatus, TreeValidationResult, TreeValidator, ValidationResult, ValidationSuccess, Validator, WithField, WithOptionalField, WithoutField };