Hello, I'd like to share a code snippet that helps keep your Angular forms strongly typed and consistent with your data interfaces. I'm working on a full-stack TypeScript project where a single set of interfaces serves as the foundation for the database models, services, DTOs, and UI components. The following snippet of code implements this concept.
import { FormArray, FormControl, FormGroup } from "@angular/forms";
export type GForm<IInterface> = FormGroup<{
[Key in keyof IInterface]:
IInterface[Key] extends Array<infer ArrayItem>
? FormArray<GForm<ArrayItem>> | FormControl<ArrayItem[]>
: IInterface[Key] extends Date
? FormControl<Date | null>
: IInterface[Key] extends object
? GForm<IInterface[Key] | null> | FormControl<IInterface[Key] | null>
: FormControl<IInterface[Key] | null>
}>;
Here's how I use it:
export interface ICar {
brand: string,
model: string,
}
form: GForm<ICar> = new FormGroup({
brand: new FormControl<string>('', [Validators.required, Validators.minLength(2)]),
model: new FormControl<string>('', [Validators.required, Validators.minLength(2)]),
});
export interface IDrivingLicence {
fullname: string;
car: ICar
}
form = new FormGroup({
fullname: new FormControl<string>(''),
car: new FormControl<ICar>(defaultCar, { nonNullable: true }),
},) as GForm<IDrivingLicence>;
I'm wondering if a similar utility already exists in the Angular library—I may have missed it. I'd appreciate it if someone could point me to a ready-made solution if one exists. My solution isn't perfect, either. It doesn't cover every edge case I've encountered. I would be grateful for any comments or suggestions on how to improve this snippet.
Notes
- The
null
type is included because a form's controls can becomenull
when the form is reset. You can still use validators to makenull
values invalid. -
FormControl<T[Key] | null>
is used for complex objects when you want to manage that object's value with a single custom form control rather than a nestedFormGroup
.
Top comments (0)