Next.js Discord

Discord Forum

Typescript: incompatible discriminating union

Answered
Large oak-apple gall posted this in #help-forum
Open in Discord
Avatar
Large oak-apple gallOP
I made simplified version of real code to showcase my error.
Problem: need to somehow allow both ImageType and VideoType to be used in component props. They have different shape of children items, thus they are distinct types
Data is coming from external source, I cannot modify its type. I can modify props of component
interface Data {
  itemsType: "image" | "video";
  items: {
    id: string;
    url?: string;
  }[];
}

type Props = ImageType | VideoType;

type ImageType = {
  itemsType: "image";
  items: {
    id: string;
    url: string;
  }[];
};

type VideoType = {
  itemsType: "video";
  items: {
    id: string;
  }[];
};

function component(props: Props) {
  console.log(props);
}

const data: Data = {
  itemsType: "video",
  items: [{ id: "1" }],
};

component({
  itemsType: data.itemsType,
  items: data.items,
});

Error:
Argument of type '{ itemsType: "image" | "video"; items: { id: string; url?: string; }[]; }' is not assignable to parameter of type 'Props'.
  Type '{ itemsType: "image" | "video"; items: { id: string; url?: string; }[]; }' is not assignable to type 'VideoType'.
    Types of property 'itemsType' are incompatible.
      Type '"image" | "video"' is not assignable to type '"video"'.
        Type '"image"' is not assignable to type '"video"'.
Answered by joulev
the problem here is that
{
  itemsType: "image";
  items: {
    id: string;
  }[];
}

is valid Data but not valid Props, that's why there is the ts error. this cannot be fixed in the type level alone, you need to check during runtime too

note here that you might want to check for the case of
{
  itemsType: "video";
  items: {
    id: string;
    url: string;
  }[];
}

too, it satisfies VideoType but having the url might not necessarily be what you want.
View full answer

4 Replies

Avatar
hmm so you can only change the types Props, ImageType and VideoType? you cannot change the Data type?
Avatar
the problem here is that
{
  itemsType: "image";
  items: {
    id: string;
  }[];
}

is valid Data but not valid Props, that's why there is the ts error. this cannot be fixed in the type level alone, you need to check during runtime too

note here that you might want to check for the case of
{
  itemsType: "video";
  items: {
    id: string;
    url: string;
  }[];
}

too, it satisfies VideoType but having the url might not necessarily be what you want.
Answer
Avatar
Large oak-apple gallOP
I see, thanks