typescript 角14中的类型化形式显示'< any>'而不是类型

d4so4syb  于 2022-11-26  发布在  TypeScript
关注(0)|答案(3)|浏览(157)

虽然是在最新版本的Angular(版本14),似乎我没有做好的东西,因此 * 严格类型 * React形式没有工作的预期。
使用注入的FormBuilderngOnInit内初始化窗体。

public form!: FormGroup;

 constructor(private formBuilder: FormBuilder) {}

 ngOnInit(): void {
    this.initializeForm();
  }

  private initializeForm(): void {
    this.form = this.formBuilder.group({
      title: ['', [Validators.required, Validators.minLength(3)]],
      content: ['', Validators.required],
    });
  }

现在,当我尝试访问表单的控件时,没有自动完成,类型为FormGroup<any>。而且,当尝试访问FormGroup对象上不存在的控件时,它也不会抛出错误。

  • 示例:

  • package.json

  • Angular 官方文件:

https://angular.io/guide/typed-forms

9rnv2umw

9rnv2umw1#

Angular文档还不够清楚,但是类型检查不适用于严格类型化的Reactive Form的原因是因为您正在OnInit钩子中初始化表单。
相反,你需要直接初始化你的表单,这样就可以推断出类型。如果你不这样做,只是给予它一个FormGroup类型,它默认为FormGroup<any>,这就是为什么你看不到Angular类型化表单的好处。
您的示例应该可以像这样重构:

@Component({
  selector: 'example',
  templateUrl: './example.component.html',
  styleUrls: ['./example.component.css']
})
export class ExampleComponent {

   public form = this.formBuilder.group({
      title: ['', [Validators.required, Validators.minLength(3)]],
      content: ['', Validators.required],
  });

  constructor(private formBuilder: FormBuilder) {}
}

我已经添加了a working example,并包含了一行被注解掉的行,这行试图设置错误的类型,如果你取消注解它,你会看到一个类型错误,编辑器会警告你。
注意--我不想粗鲁,但是@luiscla27对这个问题的公认答案是错误的,对任何发现这个SO问题的人都没有帮助,因为他们遇到了一个常见的陷阱,即不像OP那样直接初始化他们输入的React形式。

hc2pp10m

hc2pp10m2#

这里有一个解决方案,它不需要您定义接口,而是使用推断的类型

form: ReturnType<typeof this.initializeForm>
...
private initializeForm() {
  return this.formBuilder.group({
    title: ['', [Validators.required, Validators.minLength(3)]],
    content: ['', Validators.required],
  });
}
j91ykkif

j91ykkif3#

TL;DR:TypeScript识别其“类型”的方式主要是由界面和内容所决定。我建议解决这个问题的方法是明确建立界面,并将它传递给表单,因为它无法推断。

在大多数情况下; Angular将推断表单类型,只要它在声明中用正确的类型初始化。这个answer确认了那个特定的用例。

关于推断类型的注意事项,推断类型需要更多的重构工作。我的建议是始终优先选择接口而不是推断类型,当然,这条注意事项来自我自己的经验,可能会被我遗漏的一些东西所推翻。请随时告诉我,以便我可以相应地更新我的答案。

您的使用案例:

在你提供的例子中,没有办法推断出form的类型,你必须明确地告诉。我已经把this working example做成了一个类型化的表单。你在问题中包括的official documentation已经给了你大部分的答案。
要删除自动完成中的<any>,只需实现自己的接口:
第一个
此外,您的this.formBuilder.group实作已过时,因为不是类型安全的。您将需要改用AbstractControlOptions的多载(而非数组)。

private initializeForm(): void {
  this.form = this.formBuilder.group({
    title: new FormControl<string|null>(null, [Validators.required, Validators.minLength(3)]),
    content: new FormControl<string|null>(null, Validators.required)
  });
}

如下图所示,通过这些更改,您将看到键入的值{Partial<{ title: string; content: string; }>}. x1c 0d1x
你可以在typescriptlang中查看how type inference works以获得更多细节,这里有一个小的摘录:

  • 简单类型let x = 4number *

x变数的型别会被推断为number。当初始化变数和成员、设定参数预设值,以及决定函数传回型别时,就会发生这种推断。

  • 最常见的let x = [0, 1, null]类型为(number | null)[] *

在上面的例子中,我们必须考虑每个数组元素的类型。下面我们给出了两种数组类型的选择:number和null。最佳通用类型算法考虑每个候选类型,并挑选与所有其他候选类型兼容的类型。

  • 上下文类型window.onmousedown = function (mouseEvent) { ... },即MouseEvent *

上下文类型在许多情况下都适用。常见的情况包括函数调用的参数、赋值语句的右侧、类型Assert、对象和数组文本的成员以及返回语句。上下文类型还可用作最佳通用类型中的候选类型。

相关问题