Home > Enterprise >  TypeScript not seeing defined types using a type that references multiple types
TypeScript not seeing defined types using a type that references multiple types

Time:04-20

I have a type defined that looks like this:

export type MediaProps = ImageMediaProps | OembedProps;

Then have the types it's referencing defined as the following above that code:

type SharedMediaProps = {
  /** Media type */
  type: "image" | "oembed";
  /** Media source URL */
  src: string;
};

type ImageMediaProps = SharedMediaProps & {
  /** Image alternate text */
  alt: string;
  /** Image width */
  width: number;
  /** Image height */
  height: number;
};

type OembedProps = SharedMediaProps & {
  /** Enable video autoplay */
  autoplay?: boolean;
  /** Enable video loop */
  loop?: boolean;
  /** Allow fullscreen */
  allowFullscreen?: boolean;
  /** Allow picture-in-picture */
  allowPictureInPicture?: boolean;
  /** oEmbed title */
  title?: string;
};

Then in my React component, I have:

export function Media({
  type,
  title,
  width,
  height,
  src,
  autoplay = false,
  loop = false,
  allowFullscreen = true,
  allowPictureInPicture = true,
}: MediaProps) {

but I'm getting notices saying title, width, height, autoplay, loop, allowFullscreen, allowPictureInPicture aren't defined.

For example, the specific notice I'm getting is:

Property 'allowFullscreen' does not exist on type 'MediaProps'.ts(2339)

It's also happening on other components I've created.

CodePudding user response:

First, move the type property into the not shared props, so it can be used to discrimitate the type:

type SharedMediaProps = {
   /** Media source URL */
   src: string;
};

type ImageMediaProps = SharedMediaProps & {
   /** Media type */
   type: "image";
   /** Image alternate text */
   alt: string;
   /** Image width */
   width: number;
   /** Image height */
   height: number;
};

type OembedProps = SharedMediaProps & {
   /** Media type */
   type: "oembed";
   /** Enable video autoplay */
   autoplay?: boolean;
   /** Enable video loop */
   loop?: boolean;
   /** Allow fullscreen */
   allowFullscreen?: boolean;
   /** Allow picture-in-picture */
   allowPictureInPicture?: boolean;
   /** oEmbed title */
   title?: string;
};

Then define MediaProps as union of those types:

type MediaProps = ImageMediaProps | OembedProps;

After all this you still can't deconstruct the property in the paramenter because you have to discriminate the type first:

export function Media(props: MediaProps) {
   if(props.type === "image") {
      const {alt, width, height} = props;
   } else {
      const {autoplay, loop, allowFullscreen, allowPictureInPicture, title} = props;
   }
}

Demo: https://tsplay.dev/NBkVnm

CodePudding user response:

I believe you'll need to use an intersection type on your MediaProps assignment.

export type MediaProps = ImageMediaProps & OembedProps;

  • Related