Типизированные формы
Начиная с Angular 14, реактивные формы по умолчанию строго типизированы.
Для работы с этим руководством вам следует ознакомиться с реактивными формами Angular.
Обзор типизированных форм
При работе с реактивными формами Angular вы явно задаёте модель формы. В качестве простого примера рассмотрим базовую форму входа пользователя:
const login = new FormGroup({
email: new FormControl(''),
password: new FormControl(''),
});
Angular предоставляет множество API для взаимодействия с этой FormGroup. Например, можно вызвать login.value, login.controls, login.patchValue и т. д. (Полный справочник API см. в документации API.)
В предыдущих версиях Angular во многих из этих API в типах где-либо встречался any, а взаимодействие со структурой элементов управления или с самими значениями не было типобезопасным. Например, можно было написать следующий недопустимый код:
const emailDomain = login.value.email.domain;
При строго типизированных реактивных формах приведённый выше код не компилируется, поскольку у email нет свойства domain.
Помимо дополнительной безопасности, типы обеспечивают и другие улучшения, например более качественное автодополнение в IDE и явный способ задания структуры формы.
В настоящее время эти улучшения применимы только к реактивным формам (но не к формам на основе шаблонов).
Нетипизированные формы
Нетипизированные формы по-прежнему поддерживаются и продолжат работать как прежде. Чтобы использовать их, необходимо импортировать символы Untyped из @angular/forms:
const login = new UntypedFormGroup({
email: new UntypedFormControl(''),
password: new UntypedFormControl(''),
});
Каждый символ Untyped имеет ту же семантику, что и в предыдущих версиях Angular. Удаляя префиксы Untyped, вы можете постепенно включать типизацию.
FormControl: начало работы
Самая простая форма состоит из одного элемента управления:
const email = new FormControl('angularrox@gmail.com');
Для этого элемента управления автоматически будет выведен тип FormControl<string|null>. TypeScript будет автоматически проверять этот тип во всём API FormControl, например в email.value, email.valueChanges и email.setValue(...).
Допустимость значения null
Вы можете задаться вопросом: почему тип этого элемента управления включает null? Это связано с тем, что в любой момент элемент управления может стать null при вызове reset:
const email = new FormControl('angularrox@gmail.com');
email.reset();
console.log(email.value); // null
TypeScript будет требовать, чтобы вы всегда учитывали возможность того, что элемент управления стал null. Чтобы сделать этот элемент управления не допускающим null, можно использовать параметр nonNullable. Тогда элемент управления будет сбрасываться к исходному значению, а не к null:
const email = new FormControl('angularrox@gmail.com', {nonNullable: true});
email.reset();
console.log(email.value); // angularrox@gmail.com
Повторим: этот параметр влияет на поведение формы во время выполнения при вызове .reset(), поэтому изменять его следует осторожно.
Явное указание типа
Можно указать тип явно, не полагаясь на вывод типов. Рассмотрим элемент управления, инициализированный значением null. Поскольку исходное значение — null, TypeScript выведет тип FormControl<null>, который уже, чем требуется.
const email = new FormControl(null);
email.setValue('angularrox@gmail.com'); // Error!
Чтобы этого избежать, мы явно указываем тип string|null:
const email = new FormControl<string | null>(null);
email.setValue('angularrox@gmail.com'); FormArray: динамические однородные коллекции
FormArray содержит список элементов управления произвольной длины. Параметр типа соответствует типу каждого вложенного элемента управления:
const names = new FormArray([new FormControl('Alex')]);
names.push(new FormControl('Jess'));
Передайте массив элементов управления в aliases.push(), если нужно добавить сразу несколько элементов.
const aliases = new FormArray([new FormControl('ng')]);
aliases.push([new FormControl('ngDev'), new FormControl('ngAwesome')]);
У этого FormArray тип вложенных элементов управления будет FormControl<string|null>.
Если в массиве должны находиться элементы разных типов, необходимо использовать UntypedFormArray, поскольку TypeScript не может определить, какой тип элемента будет находиться на той или иной позиции.
В FormArray также есть метод clear(), удаляющий все содержащиеся в нём элементы управления:
const aliases = new FormArray([new FormControl('ngDev'), new FormControl('ngAwesome')]);
aliases.clear();
console.log(aliases.length); // 0 FormGroup и FormRecord
Angular предоставляет тип FormGroup для форм с заранее заданным набором ключей и тип FormRecord для групп с произвольными или динамическими ключами.
Частичные значения
Снова рассмотрим форму входа:
const login = new FormGroup({
email: new FormControl('', {nonNullable: true}),
password: new FormControl('', {nonNullable: true}),
});
В любом FormGroup можно отключать элементы управления. Отключённые элементы управления не будут включены в значение группы.
В результате тип login.value будет Partial<{email: string, password: string}>. Partial в этом типе означает, что значение каждого свойства может быть undefined.
В частности, тип login.value.email — string|undefined, и TypeScript потребует обработать значение, которое может быть undefined (если включён strictNullChecks).
Чтобы получить значение включая отключённые элементы управления и тем самым обойти возможные поля undefined, можно использовать login.getRawValue().
Необязательные элементы управления и динамические группы
В некоторых формах могут присутствовать или отсутствовать элементы управления, которые можно добавлять и удалять во время выполнения. Такие элементы можно представить с помощью необязательных полей:
interface LoginForm {
email: FormControl<string>;
password?: FormControl<string>;
}
const login = new FormGroup<LoginForm>({
email: new FormControl('', {nonNullable: true}),
password: new FormControl('', {nonNullable: true}),
});
login.removeControl('password');
В этой форме мы явно указываем тип, благодаря чему элемент управления password можно сделать необязательным. TypeScript будет проверять, что добавлять и удалять можно только необязательные элементы управления.
FormRecord
Некоторые варианты использования FormGroup не подходят под описанный выше шаблон, поскольку ключи заранее неизвестны. Для таких случаев предназначен класс FormRecord:
const addresses = new FormRecord<FormControl<string | null>>({});
addresses.addControl('Andrew', new FormControl('2340 Folsom St'));
В этот FormRecord можно добавить любой элемент управления типа string|null.
Если вам нужен FormGroup, который одновременно является динамическим (с произвольным числом элементов) и гетерогенным (с элементами управления разных типов), повысить безопасность типов невозможно, поэтому следует использовать UntypedFormGroup.
FormRecord также можно создать с помощью FormBuilder:
const addresses = fb.record({'Andrew': '2340 Folsom St'}); FormBuilder и NonNullableFormBuilder
Класс FormBuilder также был обновлён для поддержки новых типов, как и в приведённых выше примерах.
Кроме того, доступен ещё один построитель: NonNullableFormBuilder. Этот тип позволяет кратко задавать {nonNullable: true} для каждого элемента управления и существенно сократить шаблонный код в больших формах, не допускающих null. Получить его можно через свойство nonNullable объекта FormBuilder:
const fb = new FormBuilder();
const login = fb.nonNullable.group({
email: '',
password: '',
});
В приведённом выше примере оба вложенных элемента управления не будут допускать null (то есть для них будет задан nonNullable).
Также его можно внедрить под именем NonNullableFormBuilder.
Super-powered by Google ©2010–2025.
Code licensed under an MIT-style License. Documentation licensed under CC BY 4.0.
https://angular.dev/guide/forms/typed-forms