I'm trying to write a Typescript helper function that returns a valid either/or type but I'm not understanding how to appease the compiler. My types are defined as follows:
export interface MediaElementUrl {
media_type: 'image' | 'video';
url: string;
attachment_id: never;
buttons?: Button[];
}
export interface MediaElementAttachmentId {
media_type: 'image' | 'video';
url: never;
attachment_id: string;
buttons?: Button[];
}
export type MediaElement = MediaElementUrl | MediaElementAttachmentId;
You can have a MediaElement
that has a url
or a attachment_id
but not both. My helper class is as follows:
export class MediaElementComponent {
protected constructor(
public media_type: 'image' | 'video',
public button: Button,
public attachment_id?: string,
public url?: string
) {}
public validate(): void {
if (this.attachment_id && this.url) throw new Error('Cannot set url and attachment_id');
}
public get(): MediaElement {
if (this.attachment_id) {
return {
buttons: [this.button],
media_type: this.media_type,
attachment_id: this.attachment_id!,
};
}
return {
buttons: [this.button],
media_type: this.media_type,
url: this.url!,
};
}
}
The compiler is throwing an error on the return from get()
TS2322: Type '{ buttons: Button[]; media_type: "image" | "video"; attachment_id: string; }' is not assignable to type 'MediaElement'. Property 'url' is missing in type '{ buttons: Button[]; media_type: "image" | "video"; attachment_id: string; }' but required in type 'MediaElementAttachmentId'.
Can anyone help me understand where I'm going wrong? Thanks
CodePudding user response:
Simple fix: You need to make the forbidden properties optional:
export interface MediaElementUrl {
media_type: 'image' | 'video';
url: string;
attachment_id?: never;
buttons?: Button[];
}
export interface MediaElementAttachmentId {
media_type: 'image' | 'video';
url?: never;
attachment_id: string;
buttons?: Button[];
}
Otherwise TypeScript will enforce that these properties are present with a type of never
, which is impossible.