rdunk / sanity-blocks-vue-component

[DEPRECATED] Vue component for rendering block content from Sanity
MIT License
71 stars 10 forks source link

Using custom image serializer gives a type error #35

Open jonraem opened 2 years ago

jonraem commented 2 years ago

I'm creating a blog for myself using Sanity and Vue with TypeScript. Since I encountered some bumps on the road regarding this library, I'd like to let you know and maybe there could be something to improve. I can make a pull request later too if it's necessary. So here's the beef.

I'm not sure if the default block image serializer is supposed to work? Because without making a custom image serializer (as you will see below) the default serializer simply detected that there's an image among my blocks array and emitted an empty image tag into the DOM without any props or content.

But since I did make a custom serializer, the types of sanity-blocks-vue-component doesn't seem to like it very much. See the following simple example:

<template>
  <div>
    <div v-if="post" class="content">
      <h1>{{ post.title }}</h1>
      <SanityBlocks :blocks="blocks" :serializers="serializers" />
    </div>
  </div>
</template>

<script setup lang="ts">
import imageUrlBuilder from "@sanity/image-url";
import { SanityBlocks } from "sanity-blocks-vue-component";
import { defineComponent, h, ref } from "vue";
import type { Ref } from "vue";
import { useRoute } from "vue-router";

import sanity from "../client";

const imageBuilder = imageUrlBuilder(sanity);

const loading = ref(false);
const post: Ref<Record<string, any> | null> = ref(null);

const query = `*[slug.current == $slug] {
  _id,
  title,
  slug,
  body
}[0]
`;

function imageUrlFor(source: any) {
  return imageBuilder.image(source);
}

const serializers = {
  types: {
    image: defineComponent({
      props: ["asset"],
      setup(props) {
        return () =>
          h("img", {
            src: imageUrlFor(props.asset).width(480).url(),
          });
      },
    }),
  },
};

function fetchData() {
  const route = useRoute();
  loading.value = true;
  sanity.fetch(query, { slug: route.params.slug }).then(
    (data) => {
      loading.value = false;
      post.value = data;
    },
    (err) => {
      console.error(error);
      loading.value = false;
    }
  );
}

fetchData();
</script>

The issue comes from the SanityBlocks component's serializer prop. As I pass it my custom serializer it does work, but it gives the following type error:

Type '{ types: { image: DefineComponent<Readonly<{ asset?: any; }>, () => VNode<RendererNode, RendererElement, { [key: string]: any; }>, unknown, {}, {}, ComponentOptionsMixin, ... 5 more ..., { ...; }>; }; }' is not assignable to type 'Partial<Serializers>'.
  Types of property 'types' are incompatible.ts(2322)
types.d.ts(43, 9): 'block' is declared here.
index.d.ts(19, 5): The expected type comes from property 'serializers' which is declared here on type 'IntrinsicAttributes & Partial<{ blocks: Block[]; serializers: Partial<Serializers>; }> & Omit<Readonly<{ blocks: Block[]; serializers: Partial<...>; }> & VNodeProps & AllowedComponentProps & ComponentCustomProps, "blocks" | "serializers">'

I can supress this by setting the const serializer = { ... } as any, but it's not really a long term solution.