typescriptnext.js

Typescript error when put condition directly inside attribute of Image and Link tag in NextJs


I have this as my types

export interface ICardMovieTop {
    id: number
    poster: string
    backDrop: string
    title: string
    overview: string
    mediaType: string
    releaseDate: string
    rating: number
}

Then in my CardMovieTop component:

const CardMovieTop = ({id, poster, backDrop, title, 
      overview, mediaType, releaseDate, rating}: ICardMovieTop) => {
  
  return (
    <>
      {/* Poster on left side */}
      <div className="max-xl:hidden bg-dark rounded-l-md grow shrink-0 basis-auto w-72">
        <Image
          priority
          unoptimized
          loader={() => poster && `https://image.tmdb.org/t/p/original${poster}`}
          src={poster ? `https://image.tmdb.org/t/p/original${poster}` : 
              !poster && mediaType === "person" ? "/images/not-found-person.png" : 
              !poster && mediaType !== "person" && "/images/not-found-poster.jpg"}
          alt="Poster"
          width={0}
          height={0}
          sizes="100vw"
          className="w-full h-full object-cover rounded-l-md opacity-90"
        />
      </div>
     
        <div className="relative w-full h-full flex flex-col justify-center z-30">
          {/* Title */}
          <Link 
            href={
                mediaType === "movie" || mediaType === "tv" ? routeMovie
              : mediaType === "person" && routePerson
            } 
            title={title} 
            className="inline-block w-fit"
          >
            <h2 className="text-2xl text-white font-extrabold capitalize hover:text-tale">
              {title}{" "}
          </Link>
        </div>
    </>
  )
}

There's two error pops out for Image and Link tag above.

The Image tag problem is come from src atrribute:

src={poster ? `https://image.tmdb.org/t/p/original${poster}` : 
     !poster && mediaType === "person" ? "/images/not-found-person.png" : 
     !poster && mediaType !== "person" && "/images/not-found-poster.jpg"} 

Which said: Type 'string | false' is not assignable to type 'string | StaticImport'.

The Link tag problem is come from href atrribute:

href={mediaType === "movie" || mediaType === "tv" ? routeMovie
      : mediaType === "person" && routePerson} 

Which said: Type 'string | false' is not assignable to type 'Url'.

But it solved, no error happen, when I didn't put condition in those two tag. Like this:

Image solved: src={https://image.tmdb.org/t/p/original${poster}}

Link solved: href={mediaType}

I think Typescript didn't allow this. Because I usually did that kind of condition when only using Javascript.

Do you think there's a solution so I can use condition inside those two tag like I did above? Thank You.


Solution

  • It is because you have this expression:

    !poster && mediaType !== "person" && "/images/not-found-poster.jpg"
    

    So if !poster evaluates to true, AND mediaType !== "person" evaluates to true, then the above expression evaluates to true. But if the first two expression resolve to false, then the whole expression evaluate to false. And since that is technically possible, TS errs to side of caution. I understand that the conditions you have set are such that it might not be possible. But TS type narrowing might not be intelligent enough to do it right now. Here is an open issue where this is discussed.


    If you simplify your expression then it is definitely going to be helpful for both code readability and TS type narrowing:

    let y = poster ? `https://image.tmdb.org/t/p/original${poster}` : 
       mediaType === "person" ? "/images/not-found-person.png" :  "/images/not-found-poster.jpg";
    

    !poster can be removed as it will always be true in the first else branch.

    mediaType !== "person" can be removed as it will always be true in the second else branch.

    Now type is deciphered as string

    Playground