refactor(forms): type built-in getError results · angular/angular@e81c7e8 · GitHub
Skip to content

Commit e81c7e8

Browse files
cexbrayatpkozlowski-opensource
authored andcommitted
refactor(forms): type built-in getError results
Add overloads for built-in validation error keys so callers get precise error payload types from getError. This enables signal forms template patterns like: ```html @if (login.getError('minLength'); as minLengthError) { <div>Login should be {{ minLengthError.minLength }} characters</div> } ``` (cherry picked from commit 45e8fb5)
1 parent e3e25b5 commit e81c7e8

5 files changed

Lines changed: 79 additions & 2 deletions

File tree

goldens/public-api/forms/signals/compat/index.api.md

Lines changed: 1 addition & 0 deletions

goldens/public-api/forms/signals/index.api.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,10 @@ export type FieldContext<TValue, TPathKind extends PathKind = PathKind.Root> = T
138138
export interface FieldState<TValue, TKey extends string | number = string | number> extends ReadonlyFieldState<TValue, TKey> {
139139
readonly controlValue: WritableSignal<TValue>;
140140
readonly fieldTree: FieldTree<unknown, TKey>;
141+
getError<K extends NgValidationError['kind']>(kind: K): (Extract<NgValidationError, {
142+
kind: K;
143+
}> & ValidationError.WithFieldTree) | undefined;
144+
// (undocumented)
141145
getError(kind: string): ValidationError.WithFieldTree | undefined;
142146
markAsDirty(): void;
143147
markAsTouched(options?: MarkAsTouchedOptions): void;

packages/forms/signals/src/api/types.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
import {Injector, Signal, WritableSignal} from '@angular/core';
1010
import {AbstractControl} from '@angular/forms';
1111
import type {FormField} from '../directive/form_field';
12-
import type {MetadataKey, ValidationError} from './rules';
12+
import type {MetadataKey, NgValidationError, ValidationError} from './rules';
1313

1414
/**
1515
* Symbol used to retain generic type information when it would otherwise be lost.
@@ -545,6 +545,9 @@ export interface FieldState<
545545
* @param kind The kind of error (e.g. 'required', 'min').
546546
* @returns The first matching error, or `undefined` if none.
547547
*/
548+
getError<K extends NgValidationError['kind']>(
549+
kind: K,
550+
): (Extract<NgValidationError, {kind: K}> & ValidationError.WithFieldTree) | undefined;
548551
getError(kind: string): ValidationError.WithFieldTree | undefined;
549552

550553
/**

packages/forms/signals/src/field/node.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ import {
2525
REQUIRED,
2626
IS_ASYNC_VALIDATION_RESOURCE,
2727
} from '../api/rules/metadata';
28-
import type {ValidationError} from '../api/rules/validation/validation_errors';
28+
import type {NgValidationError, ValidationError} from '../api/rules/validation/validation_errors';
2929
import type {
3030
DisabledReason,
3131
FieldContext,
@@ -258,6 +258,10 @@ export class FieldNode implements FieldState<unknown> {
258258
return this.metadataState.get(key);
259259
}
260260

261+
getError<K extends NgValidationError['kind']>(
262+
kind: K,
263+
): (Extract<NgValidationError, {kind: K}> & ValidationError.WithFieldTree) | undefined;
264+
getError(kind: string): ValidationError.WithFieldTree | undefined;
261265
getError(kind: string): ValidationError.WithFieldTree | undefined {
262266
return this.errors().find((e) => e.kind === kind);
263267
}

packages/forms/signals/test/node/field_node.spec.ts

Lines changed: 65 additions & 0 deletions

0 commit comments

Comments
 (0)