sanity icon indicating copy to clipboard operation
sanity copied to clipboard

Querying images from the Content Lake returns the wrong type

Open nikita-bashaiev opened this issue 6 months ago • 5 comments

Describe the bug

I am trying to implement a SanityImage component in my Nextjs 14 app. Here's what I've come up with:

import { getImageDimensions, ResolvedSanityImage } from '@sanity/asset-utils';
import { getURL } from '@/lib/sanity/helpers';
import Image from 'next/image';
import { HTMLAttributes } from 'react';

interface Props extends HTMLAttributes<HTMLImageElement> {
  value: ResolvedSanityImage;
}

const SanityImage = ({ value, ...props }: Props) => {
  const { width, height } = getImageDimensions(value);
  if (value.asset) {
    return (
      <Image
        src={getURL(value).url()}
        alt=''
        loading='lazy'
        width={width}
        height={height}
        placeholder='blur'
        blurDataURL={getURL(value).height(24).width(24).blur(10).url()}
        {...props}
      />
    );
  }
};

export default SanityImage;

The getURL function looks like this:

export const getURL = (src: ResolvedSanityImage) => {
  const builder = createImageUrlBuilder(client);
  return builder.image(src);
};

However, when trying to use it to render an image queried with GROQ I get this type error:

Type '{ asset?: { _ref: string; _type: "reference"; _weak?: boolean | undefined; [internalGroqTypeReferenceTo]?: "sanity.imageAsset" | undefined; } | undefined; hotspot?: SanityImageHotspot | undefined; crop?: SanityImageCrop | undefined; _type: "image"; } | undefined' is not assignable to type 'ResolvedSanityImage'.
  Type 'undefined' is not assignable to type 'ResolvedSanityImage'.ts(2322)

Am I using the wrong types? Do I need to modify the image component? How do I make sure that the image is only rendered when value.asset is defined (as that is the problem I'm suspecting this all stems from)? Especially in scenarios such as this:

function Component1({ images }: { images: ResolvedSanityImage[] }) {
  return (
        <div className='flex'>
          {images!.map((image) => (
            <SanityImage value={image} />
          ))}
        </div>
  );
}

export default async function ProjectsPage({}: Props) {
  const projects = await sanityFetch<PROJECTS_QUERYResult>({
    query: PROJECTS_QUERY,
  });
  return (
    <div>
      {projects.map((project) => (
        <Component1 images={project.images} />
      ))}
    </div>
  );
}

To Reproduce

  1. Create a new Next app and connect Sanity
  2. Query some content with an image in the schema
  3. Copy and paste the code above

Expected behavior

No type errors.

Which versions of Sanity are you using?

@sanity/cli (global) 3.52.4 (latest: 3.54.0) @sanity/asset-utils 1.3.0 (up to date) @sanity/image-url 1.0.2 (up to date) @sanity/vision 3.52.4 (latest: 3.54.0) sanity 3.52.4 (latest: 3.54.0)

What operating system are you using?

Windows 11

Which versions of Node.js / npm are you running?

pnpm 9.7.0, node v20.12.2

nikita-bashaiev avatar Aug 20 '24 08:08 nikita-bashaiev