puck icon indicating copy to clipboard operation
puck copied to clipboard

Overriding title in RootProps makes Puck complain about data

Open knthmn opened this issue 4 months ago • 1 comments

Description

import { type Config, type Data, Puck } from "@measured/puck";
import type { UserGenerics } from "@measured/puck/dist/no-external";

type FooRootProps = {
  title: number;
};
type FooComponents = {
  Box: { size: number };
};

const testData = 0 as unknown as Data<FooComponents, FooRootProps>;
const testConfig = 0 as unknown as Config<{
  components: FooComponents;
  root: FooRootProps;
}>;

// this is ok
const y: UserGenerics<{ components: FooComponents; root: FooRootProps }> =
  testData;

function TestComponent() {
  // data has an Typescript error
  return <Puck config={testConfig} data={testData} />;
}

The error is

Type Data<FooComponents, FooRootProps> is not assignable to typePartial<Data<FooComponents, FooRootProps & DefaultRootFieldProps>>, since title is number and cannot be assigned to number & string which is never.

The issue is the following,

export type UserGenerics<
  // ...
> = {
   // ...
   UserRootProps: UserParams["rootProps"] & DefaultRootFieldProps;
   // ...
}

Environment

  • Puck version: 0.20.0, 0.20.1. No issue in 0.19.3
  • Typescript version: 5.9.2, 7.0.0 (tsgo)

knthmn avatar Aug 20 '25 13:08 knthmn

Hey @knthmn!

I can replicate the issue. Just to add more context:

The problem occurs when you change the type of root.title from a string to something else. In that case, the data is not accepted by the Puck component and a type error is thrown. If you keep it typed as a string (the default), the data is accepted and no error occurs.

This happens because of the UserGenerics.UserRootProps type definition you’re pointing to. Since title becomes an intersection between two primitive types, it becomes never and it fails.

For the record, I recommend not importing directly from "/puck/dist", but instead from "/puck". The UserGenerics type is also exposed there.

import { type Config, type Data, Puck } from "@measured/puck";

type FooRootProps = {
  title: number;
};
type FooComponents = {
  Box: { size: number };
};

const testData: Data<FooComponents, FooRootProps> = { root: {}, content: [] };

const testConfig: Config<{
  components: FooComponents;
  root: FooRootProps;
}> = {
  components: {
    Box: {
      fields: { size: { type: "number" } },
      render: ({ size }) => <div>{size}</div>,
    },
  },
};

function TestComponent() {
  // data has a TypeScript error
  return <Puck config={testConfig} data={testData} />;
}

FedericoBonel avatar Aug 21 '25 06:08 FedericoBonel