typescript 角强类型React型

esyap4oy  于 2023-03-31  发布在  TypeScript
关注(0)|答案(9)|浏览(127)

我希望在我的Angular项目中重构大量组件,以拥有强类型的FormGroups,FormArrays和FormControls。
我只是在寻找一个好的方法来实现强类型的响应式表单。谁能从自己的经验中提供建议/建议?
谢谢大家。
编辑:
澄清一下,我所说的强类型是指目前当我创建一个FormGroup或FormArray时,我无法指定其中实际表单的结构。当我将此表单传递给应用中的各个组件时,我会觉得我使它更难维护。

monwx1rj

monwx1rj1#

最优雅的解决方案是利用TypeScript声明文件(*.d.ts)来引入通用接口,扩展标准表单类,如AbstractControlFormControl等。它不引入任何新功能,在编译的JavaScript中没有足迹,但同时强制执行强类型检查。
Daniele Morosinotto在今年3月提出了这个建议,现在there are talks将其包含在Angular 9中。
采用该解决方案很简单:
1.从this gist下载TypedForms.d.ts,并将其保存为项目中的src/typings.d.ts(Angular 6+已经知道如何使用此文件)。
1.只要需要强类型验证,就可以开始使用新类型(FormGroupTyped<T>FormControlTyped<T>等)(参见that giststackblitz中的示例)。
有关更多信息,请查看blog post分析强类型表单的可用解决方案。

9vw9lbht

9vw9lbht2#

对于那些想要另一种解决方案的人。我发现this article在谈论角形的强类型。下面是我的总结。

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!
  }
}
33qvvth1

33qvvth13#

2022更新(Angular 14):类型化的React形式

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

如果你使用formBuilder服务来创建表单,你可以给它分配一个严格的类型,如下所示:

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

public myForm = this.fb.control<myType>('typeA');

如果您希望创建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}),
});
请记住,如果您不指定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');

你可以在Angular 14发布更新的博客here上了解更多信息

vs3odd8k

vs3odd8k4#

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

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) ] ],
  });
}

...

然后在模板中提交值

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

现在可以向submit函数添加类型了

onSubmit(userForm: UserFormValue) {
   ...
}

它并不完美,但对于我的用例来说已经足够好了。我真的希望有这样的东西。
userForm: FormGroup<UserFormValue>

pcrecxhr

pcrecxhr5#

严格类型的表单从Angular 14开始可用(目前在next通道上)!
FormGroupFormArray类接受泛型,这是内部控件的类型。FormControl类接受其值类型的泛型。还有一个名为FormRecord的新类,用于动态控件组。
下面是一个例子:

const party = new FormGroup({
  address: new FormGroup({
    house: new FormControl(123, {initialValueIsDefault: true}),
    street: new FormControl('Powell St', {initialValueIsDefault: true}),
  }),
  formal: new FormControl(true),
  foodOptions: new FormArray([
    new FormControl('Soup'),
  ])
});

// whichHouse has type `number`
const whichHouse = party.get('address.house')!.value;

// Error: control "music" does not exist
const band = party.controls.music;
nzk0hqpo

nzk0hqpo6#

我最终使用的解决方案是library I found called ngx-strongly-typed-forms
它使你能够拥有强类型的FormControls、FormGroups和FormArrays。虽然有一些限制,但它确实对我的项目有很大的帮助。
您可以在https://github.com/no0x9d/ngx-strongly-typed-forms上查看文档

1wnzp6jl

1wnzp6jl7#

如果你有一个嵌套类型的组,那么你可以这样做:

**型号.ts

export type TCreateUserFields = {
    first_name: string,
    last_name: string,
    accept_terms: boolean,
};
export type TPasswordsControls = {
    passwords: FormGroup & {
        password: AbstractControl,
        confirm_password: AbstractControl
    }
}
export type TPasswordsFields = {
    passwords: {
        password: string,
        confirm_password: string
    }
}
export type TAllFields = TCreateUserFields & TPasswordsFields;
export type TAllControls = TCreateUserControls & TPasswordsControls;
export type TCreateUserControls = {
    [key in keyof TCreateUserFields]: AbstractControl
};
export type TCreateUserFormGroup = FormGroup & {value: TAllFields, controls: TAllControls};

**component.ts

this.registerationForm = this.fb.group(
{
    first_name: new FormControl("", [Validators.required]),
    last_name: new FormControl("", [Validators.required]),
    accept_terms: new FormControl(false, [Validators.required]),
    passwords: new FormGroup(
        {
            password: new FormControl("", [Validators.required, Validators.pattern(/^[~`!@#$%^&*()_+=[\]\{}|;':",.\/<>?a-zA-Z0-9-]+$/)]),
            confirm_password: new FormControl("", [Validators.required, Validators.pattern(/^[~`!@#$%^&*()_+=[\]\{}|;':",.\/<>?a-zA-Z0-9-]+$/)]),
        }, { 
            validators: <ValidatorFn>pwdConfirming({key:'password', confirmationKey:'confirm_password'})
        }
    )
} as TCreateUserControls) as TCreateUserFormGroup;
iszxjhcz

iszxjhcz8#

forms.ts

import { FormControl, FormGroup } from '@angular/forms';

export type ModelFormGroup<T> = FormGroup<{
  [K in keyof T]: FormControl<T[K] | null>;
}>;

login.ts

export interface Ilogin {
  username: string;
  password: string;
}

login.component.ts

loginForm!: ModelFormGroup<Ilogin>;

constructor() {
    this.loginForm = new FormGroup({
      username: new FormControl<string | null>(null, Validators.required),
      password: new FormControl<string | null>(null, Validators.required),
    });
}
i86rm4rw

i86rm4rw9#

从Angular 14开始,默认情况下,响应式表单是严格类型化的。
https://angular.io/guide/typed-forms

interface LoginForm {
    email: FormControl<string>;
    password: FormControl<string>;
}

const login = new FormGroup<LoginForm>({
    email: new FormControl('', {nonNullable: true}),
    password: new FormControl('', {nonNullable: true}),
});

相关问题