Reputation: 21
I am creating a function that can take either control props or value, but I want the function to be able to always take all the props and decided inside which props to choose based on isControlledManually boolean value. But this doesn't work:
1st issue is that it doesn't let me use isControlled manually as boolean, it forces me to decide either false or true, but I can't pass boolean to that component. Exact error is: type 'boolean' is not assignable to type 'false'
2nd issue is even if I decide to pass only false jsut for debugging, then it yells at me, that formControl, fieldPath, selectedNonRhfValue can't be undefined
I understand both of these problems from TypeScript perspective, but how can I solve them?
export type Manual<
FormState extends FieldValues,
ItemType,
ItemValue extends string | number
> = SelectFieldQueryProps<ItemType> &
SelectFieldCommonProps<ItemType, ItemValue> & {
isControlledManually: true;
selectedNonRhfValue: ItemValue;
disabled?: boolean;
readonly?: boolean;
readonlyLabel?: string;
onChange?: (item: ItemType | null) => void;
fieldPath?: FieldPath<FormState>;
formControl?: Control<FormState>;
rules?: Omit<RegisterOptions<FormState>, 'valueAsNumber' | 'valueAsDate' | 'setValueAs' | 'disabled'>;
};
export type NotManual<
FormState extends FieldValues,
ItemType,
ItemValue extends string | number
> = SelectFieldQueryProps<ItemType> &
SelectFieldCommonProps<ItemType, ItemValue> & {
isControlledManually: false;
selectedNonRhfValue?: ItemValue;
disabled?: boolean;
readonly?: boolean;
readonlyLabel?: string;
onChange?: (item: ItemType | null) => void;
fieldPath: FieldPath<FormState>;
formControl: Control<FormState>;
rules?: Omit<RegisterOptions<FormState>, 'valueAsNumber' | 'valueAsDate' | 'setValueAs' | 'disabled'>;
};
The component is written like this without any typescript error.
export function SelectField<FormState extends FieldValues, ItemType, ItemValue extends string | number>(
props: Manual<FormState, ItemType, ItemValue> | NotManual<FormState, ItemType, ItemValue>
) {
if (props.isControlledManually === true) {
return <SelectFieldInput {...props} value={props.selectedNonRhfValue} disabled={true} />;
}
return <ControlledSelectField {...props} />;
}
The error is shown when I try to use the prepared component anywhere else, for example like this and when I do the I get the errors when passing props mentioned above.
export function QueryField<FormState extends FieldValues, ItemType, ItemValue extends string | number>(
props: Omit<
Manual<FormState, ItemType, ItemValue> | NotManual<FormState, ItemType, ItemValue>,
'data' | 'isLoading' | 'isLoadingError'
> & {
queryResult: QueryResult<ItemType[]>;
dataFilter?: (item: ItemType) => boolean;
}
) {
const getData = () => props.queryResult.data || [];
const getFilteredData = () => (props.dataFilter ? getData().filter(props.dataFilter) : getData());
return (
<SelectField
{...props}
data={getFilteredData()}
isLoading={props.queryResult.isLoading}
isLoadingError={props.queryResult.isError}
/>
);
}
Upvotes: 1
Views: 75
Reputation: 21
I found out that the issue was the whole time inside the
Omit<Manual<FormState, ItemType, ItemValue> | NotManual<FormState, ItemType, ItemValue>,'data' | 'isLoading' | 'isLoadingError'>
It turns out, you cant use Omit with unions types. You need to use custom DistributiveOmit, that can distribute across union types.
export type DistributiveOmit<T, K extends string> = T extends unknown ? Omit<T, K> : never;
Upvotes: 0