Created
December 8, 2019 23:57
-
-
Save wtho/a31de2c79580ca5ea09d6e5fd74a2a3f to your computer and use it in GitHub Desktop.
Typed Reactive Angular Forms
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
type Status = 'valid' | 'invalid'; | |
@Component({ | |
selector: 'app-component', | |
templateUrl: './app.component.html', | |
styleUrls: ['./app.component.css'] | |
}) | |
export class AppComponent { | |
profileForm = this.fb.group({ | |
f1: [''], | |
f2: [3], | |
nested: this.tfb.group({ | |
nf1: ['valid' as Status] | |
}) | |
}); | |
constructor(private fb: TypedFormBuilder) { } | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { BrowserModule } from '@angular/platform-browser'; | |
import { NgModule } from '@angular/core'; | |
import { AppComponent } from './app.component'; | |
import { FormBuilder, ReactiveFormsModule } from '@angular/forms'; | |
import { TypedFormBuilder } from './typed-form-builder'; | |
@NgModule({ | |
declarations: [ | |
AppComponent | |
], | |
imports: [ | |
BrowserModule, | |
ReactiveFormsModule | |
], | |
providers: [ | |
{provide: TypedFormBuilder, useClass: FormBuilder} | |
], | |
bootstrap: [AppComponent], | |
}) | |
export class AppModule { } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { | |
FormControl, | |
AbstractControl, | |
AsyncValidatorFn, | |
ValidatorFn, | |
FormArray, | |
FormGroup | |
} from '@angular/forms'; | |
import { Observable } from 'rxjs'; | |
// tslint:disable: callable-types | |
declare type FormHooks = 'change' | 'blur' | 'submit'; | |
export type Status = 'VALID' | 'INVALID' | 'PENDING' | 'DISABLED'; | |
export declare interface TypedAbstractControlOptions<T> { | |
validators?: TypedValidatorFn<T> | TypedValidatorFn<T>[] | null; | |
asyncValidators?: | |
| TypedAsyncValidatorFn<T> | |
| TypedAsyncValidatorFn<T>[] | |
| null; | |
} | |
export declare abstract class TypedAbstractControl<T> { | |
validator: TypedValidatorFn<T> | null; | |
asyncValidator: TypedAsyncValidatorFn<T> | null; | |
readonly value: T; | |
constructor( | |
validator: TypedValidatorFn<T> | null, | |
asyncValidator: TypedAsyncValidatorFn<T> | null | |
); | |
readonly parent: | |
| TypedFormGroup<any> | |
| TypedFormArray<any> | |
| FormGroup | |
| FormArray; | |
readonly status: Status; | |
readonly valid: boolean; | |
readonly invalid: boolean; | |
readonly pending: boolean; | |
readonly disabled: boolean; | |
readonly enabled: boolean; | |
readonly errors: TypedValidationErrors<T> | null; | |
readonly pristine: boolean; | |
readonly dirty: boolean; | |
readonly touched: boolean; | |
readonly untouched: boolean; | |
readonly valueChanges: Observable<T>; | |
readonly statusChanges: Observable<Status>; | |
readonly updateOn: FormHooks; | |
setValidators(newValidator: ValidatorFn | ValidatorFn[] | null): void; | |
setAsyncValidators( | |
newValidator: AsyncValidatorFn | AsyncValidatorFn[] | null | |
): void; | |
clearValidators(): void; | |
clearAsyncValidators(): void; | |
markAsTouched(opts?: { onlySelf?: boolean }): void; | |
markAllAsTouched(): void; | |
markAsUntouched(opts?: { onlySelf?: boolean }): void; | |
markAsDirty(opts?: { onlySelf?: boolean }): void; | |
markAsPristine(opts?: { onlySelf?: boolean }): void; | |
markAsPending(opts?: { onlySelf?: boolean; emitEvent?: boolean }): void; | |
disable(opts?: { onlySelf?: boolean; emitEvent?: boolean }): void; | |
enable(opts?: { onlySelf?: boolean; emitEvent?: boolean }): void; | |
setParent(parent: FormGroup | FormArray): void; | |
abstract setValue(value: T, options?: Object): void; | |
abstract patchValue(value: T, options?: Object): void; | |
abstract reset(value?: T, options?: Object): void; | |
updateValueAndValidity(opts?: { | |
onlySelf?: boolean; | |
emitEvent?: boolean; | |
}): void; | |
setErrors( | |
errors: TypedValidationErrors<T> | null, | |
opts?: { | |
emitEvent?: boolean; | |
} | |
): void; | |
get<K extends keyof T>(path: K): TypedAbstractControl<T[K]> | null; | |
get<K extends keyof T, K2 extends keyof T[K]>(path: [K, K2]): TypedAbstractControl<T[K][K2]> | null; | |
get<K extends keyof T, K2 extends keyof T[K], K3 extends keyof T[K][K2]>(path: [K, K2, K3]): TypedAbstractControl<T[K][K2][K3]> | null; | |
getError(errorCode: string, path?: Array<string | number> | string): any; | |
hasError(errorCode: string, path?: Array<string | number> | string): boolean; | |
readonly root: TypedAbstractControl<any>; | |
} | |
export declare type TypedValidationErrors<T> = Partial<T>; | |
export declare interface TypedValidatorFn<T> extends ValidatorFn { | |
(control: TypedAbstractControl<T>): TypedValidationErrors<T> | null; | |
} | |
export declare interface TypedAsyncValidatorFn<T> extends AsyncValidatorFn { | |
(control: TypedAbstractControl<T>): | |
| Promise<TypedValidationErrors<T> | null> | |
| Observable<TypedValidationErrors<T> | null>; | |
} | |
type TypedValidator<T> = TypedValidatorFn<T> | TypedAsyncValidatorFn<T>; | |
type MaybeFormControl<T> = | |
| TypedFormControl<T> | |
| [T] | |
| [T, TypedValidator<T>] | |
| [T, TypedValidator<T>, TypedValidator<T>] | |
| [T, TypedValidator<T>, TypedValidator<T>, TypedValidator<T>] | |
| [T, TypedValidator<T>, TypedValidator<T>, TypedValidator<T>, TypedValidator<T>] | |
| TypedFormArray<T> | |
| TypedFormGroup<T>; | |
export declare class TypedFormControl<T> extends FormControl { | |
constructor( | |
formState?: T, | |
validatorOrOpts?: | |
| TypedValidatorFn<T> | |
| TypedValidatorFn<T>[] | |
| TypedAbstractControlOptions<T> | |
| null, | |
asyncValidator?: | |
| TypedAsyncValidatorFn<T> | |
| TypedAsyncValidatorFn<T>[] | |
| null | |
); | |
setValue( | |
value: T, | |
options?: { | |
onlySelf?: boolean; | |
emitEvent?: boolean; | |
emitModelToViewChange?: boolean; | |
emitViewToModelChange?: boolean; | |
} | |
): void; | |
patchValue( | |
value: T, | |
options?: { | |
onlySelf?: boolean; | |
emitEvent?: boolean; | |
emitModelToViewChange?: boolean; | |
emitViewToModelChange?: boolean; | |
} | |
): void; | |
reset( | |
formState?: T, | |
options?: { | |
onlySelf?: boolean; | |
emitEvent?: boolean; | |
} | |
): void; | |
} | |
export declare class TypedFormGroup<G> extends TypedAbstractControl<G> { | |
controls: { | |
[K in keyof G]: TypedAbstractControl<G[K]>; | |
}; | |
constructor( | |
controls: { | |
[K in keyof G]: TypedAbstractControl<G[K]>; | |
}, | |
validatorOrOpts?: | |
| TypedValidatorFn<G> | |
| TypedValidatorFn<G>[] | |
| TypedAbstractControlOptions<G> | |
| null, | |
asyncValidator?: | |
| TypedAsyncValidatorFn<G> | |
| TypedAsyncValidatorFn<G>[] | |
| null | |
); | |
registerControl<K extends keyof G>( | |
name: K, | |
control: TypedAbstractControl<G[K]> | |
): TypedAbstractControl<G[K]>; | |
addControl<K extends keyof G>( | |
name: K, | |
control: TypedAbstractControl<G[K]> | |
): void; | |
removeControl<K extends keyof G>(name: K): void; | |
setControl<K extends keyof G>( | |
name: K, | |
control: TypedAbstractControl<G[K]> | |
): void; | |
contains<K extends keyof G>(controlName: K): boolean; | |
setValue( | |
value: { | |
[K in keyof G]: G[K]; | |
}, | |
options?: { | |
onlySelf?: boolean; | |
emitEvent?: boolean; | |
} | |
): void; | |
patchValue( | |
value: { | |
[K in keyof G]: G[K]; | |
}, | |
options?: { | |
onlySelf?: boolean; | |
emitEvent?: boolean; | |
} | |
): void; | |
reset( | |
value?: G, | |
options?: { | |
onlySelf?: boolean; | |
emitEvent?: boolean; | |
} | |
): void; | |
getRawValue(): G; | |
} | |
export declare class TypedFormArray<T> extends AbstractControl { | |
controls: TypedAbstractControl<T>[]; | |
constructor( | |
controls: TypedAbstractControl<T>[], | |
validatorOrOpts?: | |
| TypedValidatorFn<T> | |
| TypedValidatorFn<T>[] | |
| TypedAbstractControlOptions<T> | |
| null, | |
asyncValidator?: | |
| TypedAsyncValidatorFn<T> | |
| TypedAsyncValidatorFn<T>[] | |
| null | |
); | |
at(index: number): TypedAbstractControl<T>; | |
push(control: TypedAbstractControl<T>): void; | |
insert(index: number, control: TypedAbstractControl<T>): void; | |
removeAt(index: number): void; | |
setControl(index: number, control: TypedAbstractControl<T>): void; | |
setValue( | |
value: T[], | |
options?: { | |
onlySelf?: boolean; | |
emitEvent?: boolean; | |
} | |
): void; | |
patchValue( | |
value: T[], | |
options?: { | |
onlySelf?: boolean; | |
emitEvent?: boolean; | |
} | |
): void; | |
reset( | |
value?: T, | |
options?: { | |
onlySelf?: boolean; | |
emitEvent?: boolean; | |
} | |
): void; | |
getRawValue(): T[]; | |
} | |
export abstract class TypedFormBuilder { | |
abstract group<T extends object>( | |
controlsConfig: { | |
[K in keyof T]: MaybeFormControl<T[K]>; | |
}, | |
options?: | |
| TypedAbstractControlOptions<T> | |
| { | |
[K in keyof T]: T[K]; | |
} | |
| null | |
): TypedFormGroup<T>; | |
abstract control<T>( | |
formState: T, | |
validatorOrOpts?: | |
| TypedValidatorFn<T> | |
| TypedValidatorFn<T>[] | |
| TypedAbstractControlOptions<T> | |
| null, | |
asyncValidator?: | |
| TypedAsyncValidatorFn<T> | |
| TypedAsyncValidatorFn<T>[] | |
| null | |
): TypedFormControl<T>; | |
abstract array<T>( | |
controlsConfig: T[], | |
validatorOrOpts?: | |
| TypedValidatorFn<T> | |
| TypedValidatorFn<T>[] | |
| TypedAbstractControlOptions<T> | |
| null, | |
asyncValidator?: | |
| TypedAsyncValidatorFn<T> | |
| TypedAsyncValidatorFn<T>[] | |
| null | |
): TypedFormArray<T>; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment