I have an issue with type-safety while initializing a form. My problem is the following :
I basically have an interface to describe a TypedForm with a property that should accept either Enum values or the string values of the Enum.
Here's for the Enum :
export enum MyEnum {
FIRST_VALUE= 'FIRST_VALUE',
SECOND_VALUE= 'SECOND_VALUE',
}
Here's for the Type that accepts either Enum or string values :
// similar to MyEnum | 'FIRST_VALUE' | 'SECOND_VALUE'
export type MyEnumKeyValues = MyEnum | keyof typeof StringEnum;
And the Form definition :
export type MyForm = FormGroup<{
enumProperty: FormControl<MyEnumKeyValues>
}>
The problem is that, when i use FormBuilder to initialize my Form, the default value i pass in always throws a type error :
const myFormGroup: MyForm = this.formBuilder.group({
// TS2322 : Type FormControl<MyEnum> is not assignable to FormControl<MyEnumKeyValues>
enumProperty: MyEnum.FIRST_VALUE,
// TS2322 : Type FormControl<string> is not assignable to FormControl<MyEnumKeyValues>
enumProperty: 'FIRST_VALUE',
// Works but works with pretty much anything, that's not want we want here...
enumProperty: 42 as MyEnumKeyValues,
});
Note that this works but it's ugly (my real life object is much bigger, with several Enums in it) :
const myFormGroup: MyForm = this.formBuilder.group({
enumProperty: new FormControl<MyEnumKeyValues>(MyEnum.FIRST_VALUE)
});
Is there a better / more elegant way to achieve this please ? Thank you!
CodePudding user response:
The issue here is that the generic type TValue
in FormControl
is used as a function parameter in multiple methods. This makes the generic type contra-variant which leads to an error when trying to assign FormControl<MyEnum.FIRST_VALUE>
to FormControl<MyEnumKeyValues>
.
One possible solution here would be to change the type of myForm
to
export type MyForm = {
enumProperty: MyEnumKeyValues
}
and using it when building the form like this:
const myFormGroup = formBuilder.group<MyForm>({
enumProperty: MyEnum.FIRST_VALUE,
});
enumProperty
will be type checked to be one of MyEnumKeyValues
.
The type of myFormGroup
is automatically inferred to
const myFormGroup: FormGroup<{
enumProperty: FormControl<MyEnumKeyValues>;
}>