I’m trying to build a search screen that uses tabs to switch between different input methods but I’m running into a Typescript error because my base object allows multiple types whereas my custom input component doesn’t.
In the parent component I have an array of objects of type Tab to define all the tabs
export interface Tab {
id: string,
name: string,
desc: string,
type: string,
isCurrent: boolean,
value: string | number | Checkbox[] | IDate
}
I iterate over this array, and produce different HTML based on the tab type
However, because value can be multiple different data types I get errors when I try to produce checkboxes, because I need to iterate over an array. e.g. *ngFor
produces the error because tab.value
might not be an array, it might be a number etc.
<div class="govuk-form-group" *ngIf="tab.type === 'checkbox'">
<fieldset class="govuk-fieldset" aria-describedby="{tab.id + 'hint'}">
<div class="govuk-checkboxes" data-module="govuk-checkboxes">
<div class="govuk-checkboxes__item" *ngFor="let checkbox of tab.value">
<input class="govuk-checkboxes__input" id="{{checkbox.id}}" name="{{checkbox.id}}" type="checkbox" [(ngModel)]="checkbox.selected">
<label class="govuk-label govuk-checkboxes__label" for="{{checkbox.id}}">
{{checkbox.name}}
</label>
</div>
</div>
</fieldset>
</div>
I have tried to use a child component, whereby Tab.value
is redefined in the child as being of type Checkbox[]
only and passing the tab object from parent to child. But then I get an error saying that one is not assignable to the other, which makes perfect sense because value can hold different types in both Interfaces.
Is there any way I can satisfy the Type checking, without resorting to using any
?
>Solution :
Here is a way you could handle that while keeping your html exactly as is and just changing your types.
It’s a bit verbose but it lets TypeScript infer the type of the value
property from the value of the type
property
export type Tab = StringTab | NumberTab | DateTab | CheckboxTab;
interface TabBase {
id: string,
name: string,
desc: string,
isCurrent: boolean
}
interface StringTab extends TabBase {
type: "string",
value: string
}
interface NumberTab extends TabBase {
type: "number",
value: number
}
interface DateTab extends TabBase {
type: "date",
value: IDate
}
interface CheckboxTab extends TabBase {
type: "checkbox",
value: Checkbox[]
}