I have a custom Factory
type that lets me create factory functions.
export type Factory<T> = (state?: Partial<T>) => T;
I have an <Avatar />
React component that has a union type as prop because there can be two versions of it (just the image, or clickable image). In other words, the component can have either or props.
type AvatarOnlyProps = {
alt: string;
src: string;
};
type ClickableAvatarProps = {
alt: string;
label: string;
onClick:
| ((event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => void)
| undefined;
src: string;
};
export type AvatarProps = AvatarOnlyProps | ClickableAvatarProps;
I want to create a factory function for the avatar's props. I tried typing it like this:
const createProps: Factory<AvatarProps> = ({
alt = 'Your avatar',
label,
onClick,
src: source = '/images/default-avatar.png',
} = {}) => ({ alt, label, onClick, src: source });
But TypeScript complains:
Property 'label' does not exist on type 'Partial<AvatarOnlyProps> | Partial<ClickableAvatarProps>'.
in the arguments of the factory function.
How can I make the error go away? How can I get TypeScript to under stand, that in this factory function either both onClick
and label
will be supplied, or neither?
You can't destructure a property from a union unless it is included on all members of the union. label
and onClick
don't have any definition on AvatarOnlyProps
.
How can I get TypeScript to under stand, that in this factory function either both onClick and label will be supplied, or neither?
Based on how you've described your Factory
, it isn't actually the case that you have both or neither. A Factory
of T
takes an incomplete Partial<T>
and returns a complete T
. Since it accepts Partial<T>
it seems like it could accept a Partial<ClickableAvatarProps>
which has label
but not onClick
, or vice-versa.
You are setting default values for alt
and src
, but not for label
or onClick
. So if only one is supplied then only one will be returned too.
In order to properly describe this behavior, we need more than just the union of two possibilities. createProps
accepts an object with all four properties where all are optional. It returns an object with all four property keys where alt
and src
will always be string
, but label
and onClick
might be undefined
.
We need to define that returned object. Here's one way:
type AvatarProps = AvatarOnlyProps & Partial<ClickableAvatarProps>;
You can now define createProps
as Factory<AvatarProps>
and you won't have any issues.
I was able to solve it for my use case by creating the factor function with the minimal keys populated:
const createProps: Factory<AvatarProps> = ({
alt = 'Your avatar',
src: source = '/images/default-avatar.png',
...props
} = {}) => ({
alt,
src: source,
...props,
});
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.