ng-typesafe-formgroup
TypeScript icon, indicating that this package has built-in type declarations

0.0.5 • Public • Published

Angular TypeSafe Reactive Forms

Reactive FormGroups Wrapped in a Type Safe Class

Installation and Basic Usage Guide

Implemented on Angular v13.2.x


Please click on dropdowns below for further information:

Installation and Basic Integration

  • To install the package just write the command:
    npm i ng-typesafe-formgroup
    
  • Make sure that you import FormsModule and ReactiveFormsModule to the related module!
    import { FormsModule, ReactiveFormsModule } from '@angular/forms';
    
    @NgModule({
      declarations: [
        ...
      ],
      imports: [
        ...,
        FormsModule,
        ReactiveFormsModule
      ],
      providers: [],
      bootstrap: [...]
    })
    export class ...Module { }
Basic Usage
  • Either use in strong-typed fashion
    import { FormControlTypeSafe, FormGroupTypeSafe } from 'ng-typesafe-formgroup';
    
    
    interface CustomInterface{
      name: string,
      email: string,
      message: number,
    };
    
    @Component({
      selector: 'app-root',
      templateUrl: './app.component.html',
      styleUrls: ['./app.component.scss']
    })
    export class AppComponent {
    
      typeSafeFormGroup = new FormGroupTypeSafe<CustomInterface>({
        name: new FormControlTypeSafe<CustomInterface["name"]>('', [Validators.required, Validators.minLength(5)]),
        email: new FormControlTypeSafe<CustomInterface["email"]>('', [Validators.required, Validators.maxLength(30)]),
        message: new FormControlTypeSafe<CustomInterface["message"]>('', [Validators.required, Validators.maxLength(100)])
      });
    
      \* you can now directly reach the controls! *\
      ngOnInit(){
        this.typeSafeFormGroup.controls.name
        this.typeSafeFormGroup.controls.message
        this.typeSafeFormGroup.controls.email
        this.typeSafeFormGroup.controls.email.value
        this.typeSafeFormGroup.controls.email.valueChanges.subscribe(a => console.log(a));
        this.typeSafeFormGroup.valueChanges.subscribe(a => console.log(a));
      }
    
    }
  • Or use loose typing
    import { FormControlTypeSafe, FormGroupTypeSafe } from 'ng-typesafe-formgroup';
    
    
    @Component({
      selector: 'app-root',
      templateUrl: './app.component.html',
      styleUrls: ['./app.component.scss']
    })
    export class AppComponent {
      typeSafeFormGroupTypedWeak = new FormGroupTypeSafe({
        x: new FormControlTypeSafe('', [Validators.required])
      });
    
      ngOnInit(){
        this.typeSafeFormGroupTypedWeak.controls.x.value
        this.typeSafeFormGroupTypedWeak.controls.x.valueChanges.subscribe(a => console.log(a));
        this.typeSafeFormGroupTypedWeak.valueChanges.subscribe(a => console.log(a));
      }
    }
        
Discover the Package

Flexibility

Either use strong typing
  ...
  
  interface CustomInterface{
    name: string,
    email: string,
    message: number,
  };

  ...

  typeSafeFormGroup = new FormGroupTypeSafe<CustomInterface>({
    name: new FormControlTypeSafe<CustomInterface["name"]>('', [Validators.required, Validators.minLength(5)]),
    email: new FormControlTypeSafe<CustomInterface["email"]>('', [Validators.required, Validators.maxLength(30)]),
    message: new FormControlTypeSafe<CustomInterface["message"]>('', [Validators.required, Validators.maxLength(100)])
  });

  ...

and this way forms will asset your values on typeSafeFormGroup.valueChanges and typeSafeFormGroup.value such as ;

 typeSafeFormGroup.valueChanges.subscribe(val => val); \* val asserted as CustomInterface *\
 typeSafeFormGroup.value \* value asserted as CustomInterface \*

so that value is asserted correctly, unlike normal FormGroup class asserts everything as any!


Or use loose typing. It still prevents you try to reach undefined control or mistype the control name in the group. But providing interface stricts you on form controls you add.
  typeSafeFormGroupTypedWeak = new FormGroupTypeSafe({
    x: new FormControl('', [Validators.required])
  });

  constructor(){}

  ngOnInit(){
    this.typeSafeFormGroupTypedWeak.controls.x /* OK!
    this.typeSafeFormGroupTypedWeak.controls.a /* X->error! a is not a member of constructor object
  }







Important note

Be careful on value assertions. If you declare and interface and provide it to form group, values asserted on property types of interface. For example:

  interface CustomInterface{
    name: string,
    email: string,
    message: number,
  };

  typeSafeFormGroup = new FormGroupTypeSafe<CustomInterface>({
    name: new FormControlTypeSafe<CustomInterface["name"]>('', [Validators.required, Validators.minLength(5)]),
    email: new FormControlTypeSafe<CustomInterface["email"]>('', [Validators.required, Validators.maxLength(30)]),
    message: new FormControlTypeSafe<CustomInterface["message"]>('', [Validators.required, Validators.maxLength(100)])
  });

  this.typeSafeFormGroup.controls.email.value -> asserted as: string | number , because types on CustomInterfaces are string | number
  this.typeSafeFormGroup.controls.email.valueChanges.subscribe(a => console.log(a)); -> 'a' asserted as string | number
  this.typeSafeFormGroup.valueChanges.subscribe(a => console.log(a)); -> 'a' asserted as CustomInterface
  this.typeSafeFormGroup.value -> asserted as CustomInterface

If you don't provide an interface values asserted as "unknown". If you want to assign the value for example to a string (you expect it coming from the form), just basically do:

  typeSafeFormGroupTypedWeak = new FormGroupTypeSafe({
    x: new FormControlTypeSafe('', [Validators.required])
  });

  let x:string = <unknown> this.typeSafeFormGroupTypedWeak.controls.x.value as string;
  this.typeSafeFormGroupTypedWeak.controls.x.valueChanges.subscribe(a => a);



  this.typeSafeFormGroupTypedWeak.controls.x.value -> asserted as unknown

Please note that you can still use FormControl inside FormGroupTypeSafe instead of FormControlTypeSafe, but it's recommended to use FormControlTypeSafe.

Type safe forms prevents you from making mistakes

  • Transpiler warns you if you try to access an invalid control
  typeSafeFormGroupTypedWeak = new FormGroupTypeSafe({
    x: new FormGroupTypeSafe('', [Validators.required])
  });

  constructor(){}

  ngOnInit(){
    this.typeSafeFormGroupTypedWeak.controls.x /* OK!
    this.typeSafeFormGroupTypedWeak.controls.a /* X->error! a is not a member of constructor object
  }
  • If you provide an interface, you can not define a control that is not defined in the interface you provide
  interface FormControls{
    name: string,
    email: string,
    message: number,
  };

  typeSafeFormGroup = new FormGroupTypeSafe<FormControls>({
    name: new FormControlTypeSafe('', [Validators.required, Validators.minLength(5)]),
    email: new FormControlTypeSafe('', [Validators.required, Validators.maxLength(30)]),
    message: new FormControlTypeSafe('', [Validators.required, Validators.maxLength(100)]),
    outlier: new FormControlTypeSafe('', [Validators.required, Validators.maxLength(100)]) // X-> error! 'outlier' is not  FormControls property!
  })

Package Sidebar

Install

npm i ng-typesafe-formgroup

Weekly Downloads

0

Version

0.0.5

License

MIT

Unpacked Size

19.9 kB

Total Files

12

Last publish

Collaborators

  • ephateehe