Typisierte Form in Angular 14 zeigt `<any>` anstelle von Typen

Während ich die neueste Version von Angular (Version 14) verwende, scheint es, dass ich etwas nicht gut mache und daher funktionieren streng typisiert reaktive Formulare nicht wie erwartet.

Das Formular wird innerhalb von ngOnInit mit eingespritztem FormBuilder initialisiert.

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

Wenn ich jetzt versuche, auf die Steuerelemente des Formulars zuzugreifen, gibt es keine automatische Vervollständigung und der Typ ist FormGroup<any>. Außerdem wird der Fehler nicht ausgegeben, wenn versucht wird, auf Steuerelemente zuzugreifen, die nicht auf dem FormGroup-Objekt vorhanden sind.

  • Beispiel:

Typisierte Form in Angular 14 zeigt `&lt;any&gt;` anstelle von Typen

  • package.json

Typisierte Form in Angular 14 zeigt `&lt;any&gt;` anstelle von Typen

  • Winkel offizielle Dokumentation:

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

🤔 А знаете ли вы, что...
Angular предоставляет средства для тестирования приложений, включая юнит-тестирование и интеграционное тестирование.


521
2

Antworten:

Gelöst
TL;DR: Die Art und Weise, wie TypeScript seine „Typen“ identifiziert, hängt hauptsächlich von Schnittstellen und Kontext ab. Verwenden Sie zum Lösen eine explizite Schnittstelle und übergeben Sie sie an das Formular, da sie nicht abgeleitet werden kann.

Sie können wie Typinferenz funktioniert für weitere Details in Typescriptlang überprüfen, hier ist ein kleiner Auszug:

Einfacher Typ let x = 4 Wesen number

The type of the x variable is inferred to be number. The kind of inference takes place when initializing variables and members, setting parameter default values, and determining function return types.

Bester gemeinsamer Typ let x = [0, 1, null] ist Typ (number | null)[]

To infer the type of x in the example above, we must consider the type of each array element. Here we are given two choices for the type of the array: number and null. The best common type algorithm considers each candidate type, and picks the type that is compatible with all the other candidates.

Kontextuelle Typen window.onmousedown = function (mouseEvent) { ... }, Sein MouseEvent

Contextual typing applies in many cases. Common cases include arguments to function calls, right hand sides of assignments, type assertions, members of object and array literals, and return statements. The contextual type also acts as a candidate type in best common type.


Ihr Anwendungsfall:

Es gibt keine Möglichkeit, auf den form-Typ zu schließen, Sie müssen es explizit angeben. Ich habe dieses Arbeitsbeispiel aus einem getippten Formular erstellt. Der amtliche Dokumentation, den Sie in Ihre Frage aufgenommen haben, gibt Ihnen bereits den größten Teil der Antwort.

Um das <any>, das Sie in Ihrer Autovervollständigung sehen, zu entfernen, implementieren Sie einfach Ihre eigene Schnittstelle:

export interface IMainForm {
    title: FormControl<string>;
    content: FormControl<string>;
}
public form!: FormGroup<IMainForm>; // <--- Use your interface

Auch Ihre Implementierung von this.formBuilder.groupist veraltet, weil ist nicht typsicher. Sie müssen stattdessen die Überladung mit AbstractControlOptions verwenden (nicht mit dem Array).

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

Wie Sie im folgenden Bild sehen können, sehen Sie mit diesen Änderungen den eingegebenen Wert {Partial<{ title: string; content: string; }>}.


Hier ist eine Lösung, bei der Sie keine Schnittstelle definieren müssen, sondern den abgeleiteten Typ verwenden

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