New bug with Prismic & Typescript with new update - incompatible with index signature & is not assignable to type

Hello,

I am again fixing full blocker issues following a new update/fix of Slicemachine:

Type '{ blog_post_banner: ComponentType<BlogPostBannerProps>; content_block: ComponentType<TextContentProps>; ... 19 more ...; text_content: ComponentType<...>; }' is not assignable to type 'Record<string, SliceComponentType<any, unknown>>'.ts(2322)
SliceZone.d.ts(150, 5): The expected type comes from property 'components' which is declared here on type 'IntrinsicAttributes & SliceZoneProps<unknown>'
(property) components?: Record<string, SliceComponentType<any, unknown>> | undefined
A record mapping Slice types to React components.

I do not understand why every update is breaking everything :sweat_smile:

I have isolated that branch, everything is fine if I work on another branch if I am not doing that upgrade of slicemachine, so it definitely has to do with this upgrade?

Hi @Marving!

The TypeScript issue is definitely not intentional.

It looks like one or more of your Slice components do not adhere to SliceComponentType. The SliceComponentType type enforces that a Slice component accepts the following props:

  • slice: The Slice object being rendered.
  • index: The index of the Slice within the Slice Zone.
  • slices: The list of all Slice objects in the Slice Zone.
  • context: Arbitrary data passed to the <SliceZone>'s context prop.

You can learn more about these props in the <SliceZone> documentation here: @prismicio/react Technical Reference - Documentation - Prismic

Slice components should be typed like the example provided here: Use TypeScript with Next.js - Documentation - Prismic

// src/slices/Text/index.tsx

import type { Content } from '@prismicio/client'
import type { SliceComponentProps } from '@prismicio/react'

export type TextProps = SliceComponentProps<Content.TextSlice>

export default function Text({ slice }: TextProps) {
  // `slice` is typed as TextSlice.
}

Note the use of SliceComponentProps and Content.

If this does not resolve the TypeScript error, we will need more information to understand the issue. You can get the full TypeScript error by running the following command in your project:

npx tsc --noEmit

If you receive more errors than the one you shared above, please share only the SliceComponentType error so we can pinpoint the issue.

Thanks! :slightly_smiling_face:

Hello @angeloashmore, thank you for coming back to me!

Weirdly, I do not have that issue anymore when trying on another brand new branch... (Have tried that previously on a new branch, and the issue was coming out again).

The thing is, that the whole application is in TypeScript, but we kept the slices in Javascript so far (index.js). So even weirder that this kind of bug popped out. Maybe it forced the rewriting of the slices as .ts with the same content, I dont know...

The only warning I got re-installing it now is:

 WARN  Issues with peer dependencies found
.
└─┬ slice-machine-ui 1.0.3
  └─┬ @prismicio/editor-fields 0.3.0
    └── ✕ unmet peer @prismicio/editor-ui@0.3.0: found 0.3.1 in slice-machine-ui

I will investigate further in this end of week, I will reopen that ticket if the issue comes back in any form.

Thank you for your assistance in the meantime!!

You're welcome, @Marving!

That peer dependency warning should be safe to ignore. If it is blocking your project from installing dependencies, you can install them with the --legacy-peer-deps flag.

npm install --legacy-peer-deps

I notified the Slice Machine development team of the issue. I don't have an estimate on when the fix will be published, but they are aware of it. :slight_smile:

1 Like

Appreciate it Angelo, thank you!!!

Hello @angeloashmore,

Actually the error is back following me creating a new slice type:

Type error: Type '{ all_blog_posts: ComponentType<{}>; blog_post_banner: ComponentType<BlogPostBannerProps>; content_block: ComponentType<TextContentProps>; ... 19 more ...; text_content: ComponentType<...>; }' is not assignable to type 'Record<string, SliceComponentType<any, unknown>>'.
  Property 'all_blog_posts' is incompatible with index signature.
    Type 'ComponentType<{}>' is not assignable to type 'SliceComponentType<any, unknown>'.
      Type 'ComponentClass<{}, any>' is not assignable to type 'SliceComponentType<any, unknown>'.
        Type 'ComponentClass<{}, any>' is not assignable to type 'ComponentClass<SliceComponentProps<any, unknown>, any>'.
          Construct signature return types 'Component<{}, any, any>' and 'Component<SliceComponentProps<any, unknown>, any, any>' are incompatible.
            The types of 'props' are incompatible between these types.
              Type 'Readonly<{}>' is missing the following properties from type 'Readonly<SliceComponentProps<any, unknown>>': slice, index, slices, context

Could it be because my old slices are still a .js file (index.js)? But my new one, for instance the one that triggered the but, is in TS (index.tsx):

import { Content } from '@prismicio/client'
import { SliceComponentProps } from '@prismicio/react'
import { PrismicRichText } from '@prismicio/react'
import { ReactElement } from 'react'

/**
 * Props for `HeaderBasic`.
 */
export type HeaderBasicProps = SliceComponentProps<Content.HeaderBasicSlice>

/**
 * Component for "HeaderBasic" Slices.
 */
const HeaderBasic = ({ slice }: HeaderBasicProps): ReactElement => {
  return (
    <section
      data-slice-type={slice.slice_type}
      data-slice-variation={slice.variation}
    >
      <div className="bg-bluer-1000 px-6 py-24 sm:py-32 lg:px-8">
        <div className="mx-auto max-w-2xl text-center">
          <PrismicRichText
            field={slice.primary.title}
            components={{
              heading2: ({ children }) => (
                <h2 className="text-4xl font-bold tracking-tight text-white sm:text-6xl">
                  {children}
                </h2>
              )
            }}
          />

          <PrismicRichText field={slice.primary.title} />
          <p className="mt-6 text-lg leading-8 text-gray-300">
            {slice?.items?.map((item, i) => (
              <PrismicRichText field={item.paragraphs} key={i} />
            ))}
          </p>
        </div>
      </div>
    </section>
  )
}

export default HeaderBasic

Hey @Marving,

The TypeScript error says there's something wrong with the all_blog_posts Slice.

Could you post your AllBlogPosts component here? You don't need to include the contents of the component; main thing we need to see is its types.

My guess is that AllBlogPosts is not using SliceComponentProps with Content.AllBlogPostsSlice.

@angeloashmore,

This slice has been deleted actually (all_blog_posts). Redeleted it from slicemachine.
Now its blog_post_banner the issue:

./pages/[uid].tsx:57:9
Type error: Type '{ blog_post_banner: ComponentType<BlogPostBannerProps>; content_block: ComponentType<TextContentProps>; ... 19 more ...; text_content: ComponentType<...>; }' is not assignable to type 'Record<string, SliceComponentType<any, unknown>>'.
  Property 'data_guide_cta' is incompatible with index signature.
    Type 'ComponentType<{}>' is not assignable to type 'SliceComponentType<any, unknown>'.
      Type 'ComponentClass<{}, any>' is not assignable to type 'SliceComponentType<any, unknown>'.
        Type 'ComponentClass<{}, any>' is not assignable to type 'ComponentClass<SliceComponentProps<any, unknown>, any>'.
          Construct signature return types 'Component<{}, any, any>' and 'Component<SliceComponentProps<any, unknown>, any, any>' are incompatible.
            The types of 'props' are incompatible between these types.
              Type 'Readonly<{}>' is missing the following properties from type 'Readonly<SliceComponentProps<any, unknown>>': slice, index, slices, context

  55 |       <SliceZone
  56 |         slices={page.data.slices}
> 57 |         components={components}
     |         ^
  58 |         context={{ similarPages }}
  59 |       />
  60 |       <Statistics />

I think it's just showing the first slice by alphabetical order basically.
Here's for instance the BlogPostBanner slice as index.js:

import { PrismicRichText } from '@prismicio/react'

/**
 * @typedef {import("@prismicio/client").Content.BlogPostBannerSlice} BlogPostBannerSlice
 * @typedef {import("@prismicio/react").SliceComponentProps<BlogPostBannerSlice>} BlogPostBannerProps
 * @param { BlogPostBannerProps }
 */
const BlogPostBanner = ({ slice }) => (
  <section className="bg-[#001632] py-20 px-10 mb-20">
    <div className="container-constrained">
      <div className="text-center text-4xl font-semibold text-white">
        <PrismicRichText field={slice.primary.title} />
      </div>
    </div>
  </section>
)

export default BlogPostBanner

So is it because slicemachine is expected all my slices (index) to be typescripted (index.tsx)?

I don't think that's the case because we can see that other Slice components have correct types.

For example, blog_post_banner: ComponentType<BlogPostBannerProps> means that the BlogPostBanner component receives BlogPostBannerProps props.

The error says data_guide_cta (DataGuideCTA) doesn't have the correct props.

Could you check that component? If it looks okay, could you post its code here?

Good catch @angeloashmore . Seems like I have to debug them one by one:

It seems that now that "slices" is typed,I am:

  1. Forced to pass "{ slice }"
  2. And having a section defining the Slice type on each slice index.js, e.g:
import JobsAlertCta from '@/components/JobsAlertCta'
/**
 * @typedef {import("@prismicio/client").Content.JobsAlertCtaSlice} JobsAlertCtaSlice
 * @typedef {import("@prismicio/react").SliceComponentProps<JobsAlertCtaSlice>} JobsAlertCtaProps
 * @param { JobsAlertCtaProps }
 */
const JobsAlertCtaSlice = ({ slice }) => <JobsAlertCta />

export default JobsAlertCtaSlice

I dont know if that jumped or else during the update, or if it was never required before, but is there a way to automatically regenerate it for all slices? that @param @typedef part?

That is not totally related but still - Making sure there's not a bug in the patch:

I have deleted a legacy slice named "quote" from slicemachine. The index.js and schema json of this slice has been correctly deleted automatically. Although, unfortunately, it seems that the master slices>index.js importing all the slices has not been automatically updated, because I am still seeing the importation of this deleted slice:

./slices/index.js:18:0
Module not found: Can't resolve './Quote'
  16 | import NewsletterBasic from './NewsletterBasic'
  17 | import PillarBanner from './PillarBanner'
> 18 | import Quote from './Quote'

How come? Is it not automatically updated anymore?