typescript - Hur man använder unionstyper på HTML-mallsidan av en Angular-komponent
I HTML-delen av en Angular-komponent vill jag visa en kryssruta eller en ikon under olika villkor. Med en tillåtande modell { checked?: boolean; icon?: string } kan jag göra det så här:
<input type="checkbox" [(ngModel)]="item.checked" *ngIf="!item.icon">
<i class="{{item.icon}}" *ngIf="item.icon">
Denna modell tillåter ogiltiga tillstånd som att ha både checked och icon. Att ha en starkare modell skulle kunna förlita sig på en unionstyp: { checked: boolean } | { icon: string }. Men det fungerar inte längre i HTML, eftersom varken checked eller icon är tillgängliga på "unionstypnivån" utan bara i vänster- eller högerscénariot.
Finns det ett sätt att använda den här modellen i någon modifierad HTML-mall?
Svar #1
Det är lite sent, men jag har ett liknande problem just nu. Jag har hittat en lösning, men den är inte särskilt elegant. Jag hoppas att det finns något bättre... Du kan linda ditt objekt i $any()-operatorn så här:
<input type="checkbox" [(ngModel)]="$any(item).checked" *ngIf="!item.icon">
<i class="{{$any(item).icon}}" *ngIf="item.icon">
Det borde fungera.
Svar #2
Det här är inte lösningen jag förväntade mig utan en justering
Vi kan typa vårt item med unionstypen och fortfarande använda det i HTML-mallen men via en tweak-funktion som bara justerar typen för att göra de två innersta typerna kompatibla med varandra. Så idén är att använda ett "tweakat item" i HTML-mallen och fortfarande använda ett vanligt item i resten av TypeScript-koden.
Här är ett demokod i TypeScript där props simulerar användningen som görs i HTML-mallen:
type Item =
| { checked: boolean }
| { icon: string };
const items: Item[] = [{ checked: true }, { icon: 'checked' }];
const propsKo = items.map(x => ({ checked: x.checked, icon: x.icon }));
// ~~~~~~~ ~~~~
// 💥 Property 'xxx' (icon/checked) does not exist on type 'Item'
// 💡 Tweak
type ItemTweaked =
| { checked: boolean; icon: never }
| { icon: string; checked: never };
const tweak = (item: Item) => item as ItemTweaked;
const propsOk = items.map(tweak).map(x => ({ checked: x.checked, icon: x.icon }));
// ^^^^^
