0

Angular eingeführt Modellgetriebene bildet mit seiner Formbuilder Klasse, deren primäre Methode group hat eine Signatur wie folgt aus:fester Länge Array mit optionalen Elemente in Maschinenschrift Schnittstelle

group(controlsConfig: { 
     [key: string]: any; 
    }): FormGroup; 

Die any ist eigentlich ein Array mit dem Format :

[ 
    initial value of model's property, 
    sync validator(s), 
    async validator(s) 
] 

Wo nur das erste Element benötigt wird.

Ich entscheide ich etwas mehr stark typisiert als die möchten, vor allem auf alles, was mit einem stark typisierte Modell verknüpft ist, so dass ich neu definieren, die Funktion in Bezug auf T:

declare interface FormBuilder2 extends FormBuilder { 
    group<T>(controlsConfig: { 
     [K in keyof T]?: [T[K], ValidatorFn | ValidatorFn[] | null, ValidatorFn | ValidatorFn[] | null]; 
    }): FormGroup; 
} 

Das bedeutet auch, dass alle meine formControlNames im HTML (und natürlich hier im Aufruf von group()) den Eigenschaften des Modells entsprechen müssen, die ich bevorzuge.

Es scheint aber für ein Schlamassel zu arbeiten:

this.optionsForm = this.formBuilder2.group<CustomerModel>({ 
     status: [this.model.status, [Validators.required], null], 
     lastOrder: [this.model.lastOrder, null, null], 
     comments: [this.model.comments, null, null], 
    }); 

I null auf den nicht verwendeten Array-Slots zur Verfügung stellen müssen.

Gibt es eine Möglichkeit, Typoskript zu erhalten, um die überflüssigen null s wegzulassen?

Antwort

1

Es gibt keine wirklich typsichere Möglichkeit, dies mit Tupeltypen zu tun, da Tupel zusätzliche Elemente akzeptieren können. Das heißt, zum Beispiel akzeptiert der Tupeltyp [A, B, C] zusätzliche Elemente des Typs A | B | C (see docs).

Es gibt jedoch eine Lösung! (Siehe Versuch 3 unten)

(Übrigens, haben Sie übersehen, dass Angular einen Unterschied Schnittstelle für async Validatoren hat. AsyncValidatorFn)

Versuch 1:

[K in keyof T]?: [T[K] | ValidatorFn | ValidatorFn[] | null]; 

Kaum besser als any tippen (möglicherweise schlechter, weil es irreführend aussagekräftig aussieht).

Versuch 2:

[K in keyof T]?: 
    [T[K]] | 
    [T[K], ValidatorFn | ValidatorFn[]] | 
    [T[K], ValidatorFn | ValidatorFn[] | null, AsyncValidatorFn | AsyncValidatorFn[]]; 

scheint besser auf den ersten Blick. Das Problem ist jedoch, dass der Typescript-Compiler nur als letzten Ausweg einen Fehler erzeugt. So wird es dieses annehmen:

someStringField: ['hi', 'hello'] 

Da dies [T[K]] entspricht (als Tupel in Typoskript erlaubt sind zusätzliche Elemente zu haben).

Versuch 3:

Es gibt eine bessere Lösung, viel zu meinem Erstaunen. Ich habe das herausgefunden, als ich diese Antwort geschrieben habe, während ich this issue auf dem Typescript GitHub Repo gelesen habe.

[K in keyof T]?: { 
    0: T[K]; 
    1?: ValidatorFn | ValidatorFn[]; 
    2?: AsyncValidatorFn | AsyncValidatorFn[]; 
}; 

Dies ist eine Verbesserung gegenüber dem vorherigen Versuch, da die ersten drei Elemente immer korrekt typgeprüft werden. ['hi', 'hello'] gibt einen Kompilierungsfehler korrekt. Zusätzliche Elemente sind erlaubt und können alles sein, wie bei der üblichen strukturellen Typisierung, aber das ist in Ordnung.

Hoffe das löst Ihr Problem.

+0

Clever! Und ja, ich wusste, dass zusätzliche Elemente möglich sind, aber das ist akzeptabel. (Auch +1 für mein AsyncValidatorFn Miss.) –

Verwandte Themen