Angular 强类型反应形式

Tom*_*mbe 16 typescript reactive-forms angular angular-reactive-forms

我希望重构我的 Angular 项目中的大量组件,以拥有强类型的 FormGroups、FormArrays 和 FormControls。

我只是在寻找一种实现强类型反应形式的好方法。任何人都可以根据自己的经验提供建议/建议吗?

谢谢你。

编辑:

澄清一下,强类型是指当前当我创建 FormGroup 或 FormArray 时,我无法指定其中的实际表单的结构。当我将此表单传递给我的应用程序中的各种组件时,我觉得我变得更难维护了。

Anh*_*INH 20

对于那些想要其他解决方案的人。我发现这篇文章谈论的是有角形式的强类型。下面是我的总结。

interface Person {
  name: string;
  email: string
}

// Controls in a form group that would emit a Person as it's value
type PersonControls = { [key in keyof Person]: AbstractControl };
type PersonFormGroup = FormGroup & { value: Person, controls: PersonControls };

export class MyFormComponent {
  form = new FormGroup({
    name: new FormControl(),
    email: new FormControl()
  } as PersonControls) as PersonFormGroup;

  init() {
    const name = this.form.controls.name; // strong typed!
  }
}
Run Code Online (Sandbox Code Playgroud)

  • 我更喜欢这个。谢谢! (3认同)

Hos*_*avi 18

2022 更新(Angular 14):类型化反应形式

随着 Angular 的最新更新,响应式表单的严格类型已经实现!并且不需要解决方法。

如果您使用formBuilder服务来创建表单,您可以为其分配严格类型,如下所示:

type myType = 'typeA' | 'typeB' | 'typeC';

public myForm = this.fb.control<myType>('typeA');
Run Code Online (Sandbox Code Playgroud)

如果您更喜欢创建一个formGroup无关的formBuilder服务,那么您可以通过以下方式实现这一目标:

interface User {
    name: FormControl<string>;
    email: FormControl<string>;
    isAdmin: FormControl<boolean>;
}

public user: FormGroup<User> = new FormGroup<User>({
    name: new FormControl('', {nonNullable: true}),
    email: new FormControl('', {nonNullable: true}),
    isAdmin: new FormControl(false, {nonNullable: true}),
});
Run Code Online (Sandbox Code Playgroud)
请记住,如果您不指定该nonNullable属性,您的模板中可能会出现关于您的值为 的错误null。特别是当您想将表单控件的值绑定到某些内容时。

即使您没有明确写下类型,Angular 也会自动检查类型系统,如下所示:

const cat = new FormGroup({
   name: new FormGroup({
      first: new FormControl('Barb'),
      last: new FormControl('Smith'),
   }),
   lives: new FormControl(9),
});

// Type-checking for forms values!
// TS Error: Property 'substring' does not exist on type 'number'.
let remainingLives = cat.value.lives.substring(1);

// Optional and required controls are enforced!
// TS Error: No overload matches this call.
cat.removeControl('lives');

// FormGroups are aware of their child controls.
// name.middle is never on cat
let catMiddleName = cat.get('name.middle');
Run Code Online (Sandbox Code Playgroud)

您可以在其博客上的 Angular 14 版本更新中了解更多相关信息


Ale*_*aus 16

最优雅的解决方案是利用打字稿声明文件(*.d.ts)来介绍扩展标准表格类,如通用接口AbstractControlFormControl等它不引入任何新的功能,并已在编译的JavaScript不留痕迹,但在同一时间执行强有力的类型检查。

这是Daniele Morosinotto 在今年 3 月提出的建议,现在正在讨论将其包含在 Angular 9 中。

采用解决方案很简单:

  1. TypedForms.d.ts这个 gist下载并将它保存src/typings.d.ts在你的项目中(Angular 6+ 已经知道如何使用这个文件)。
  2. 每当您需要强类型验证时,就开始使用新类型(FormGroupTyped<T>FormControlTyped<T>等)(请参阅该 giststackblitz 中的示例)。

有关更多信息,请查看分析强类型表单可用解决方案的博客文章


小智 5

我有类似的问题,这是我的解决方案。我真的只关心表单“值”的类型而不是表单本身。它最终看起来像这样。

export interface UserFormValue {
  first_name: string
  last_name: string
  referral: string
  email: string
  password: string
}
...

ngOnInit() {
  this.userForm = this.fb.group({
    first_name: [ '', Validators.required ],
    last_name: [ '', Validators.required ],
    referral: [ '' ],
    email: [ '', [ Validators.required, Validators.email ] ],
    password: [ '', [ Validators.required, Validators.minLength(8) ] ],
  });
}

...
Run Code Online (Sandbox Code Playgroud)

然后在模板中提交值

<form [formGroup]="userForm" (ngSubmit)="onSubmit(userForm.value)">
   ...
</form>

Run Code Online (Sandbox Code Playgroud)

现在您可以向提交函数添加类型

onSubmit(userForm: UserFormValue) {
   ...
}
Run Code Online (Sandbox Code Playgroud)

它并不完美,但对于我的用例来说已经足够好了。我真希望有这样的地方。

userForm: FormGroup<UserFormValue>