payload icon indicating copy to clipboard operation
payload copied to clipboard

Images has a wrong types attached to it

Open firstaxel opened this issue 1 year ago • 12 comments

Describe the Bug.

Good evening please i have been getting wrong types when i use upload field type in payload

export interface Testimonial {
  id: number;
  quote: string;
  name: string;
  designation: string;
  **src: number | Media;**
  updatedAt: string;
  createdAt: string;
}

I made emphasis on the src type generated for media in payload

it is gives me issue when i want to use typescript also i cant edit it cause it is generated everytime on a request is made to payload

Reproduction Steps

i created my schema like this one below import type { CollectionConfig } from "payload" import { Media } from "./Media"

export const CaseStudies: CollectionConfig = {
  slug: "case-studies",
  access: {
    read: () => true,
  },
  fields: [
    {
      name: "title",
      type: "text",
      required: true,
    },

    {
      name: "gallery",
      type: "array",
      fields: [
        {
          name: "image",
          type: "upload",
          relationTo: "media",
          required: true,
        },
      ],
    },
    {
      name: "link",
      type: "text",
    },
    {
      name: "description",
      type: "text",
    },
  ],
}

payload config

// storage-adapter-import-placeholder
import { postgresAdapter } from "@payloadcms/db-postgres"
import { payloadCloudPlugin } from "@payloadcms/payload-cloud"
import { lexicalEditor } from "@payloadcms/richtext-lexical"
import path from "path"
import { buildConfig } from "payload"
import { fileURLToPath } from "url"
import sharp from "sharp"
import { uploadthingStorage } from "@payloadcms/storage-uploadthing"

import { Users } from "./collections/Users"
import { Media } from "./collections/Media"
import { CaseStudies } from "./collections/CaseStudies"
import { Brands } from "./collections/Brands"
import { Testimonials } from "./collections/Testimonials"

const filename = fileURLToPath(import.meta.url)
const dirname = path.dirname(filename)

export default buildConfig({
  admin: {
    user: Users.slug,
    importMap: {
      baseDir: path.resolve(dirname),
    },
  },
  collections: [Users, Media, CaseStudies, Brands, Testimonials],
  editor: lexicalEditor(),
  secret: process.env.PAYLOAD_SECRET || "",
  typescript: {
    outputFile: path.resolve(dirname, "payload-types.ts"),
  },
  db: postgresAdapter({
    pool: {
      connectionString: process.env.DATABASE_URI || "",
    },
  }),
  sharp,
  plugins: [
    payloadCloudPlugin(),
    // storage-adapter-placeholder
    uploadthingStorage({
      collections: {
        media: true,
      },
      options: {
        token: process.env.UPLOADTHING_TOKEN,
        acl: "public-read",
      },
    }),
  ],
})

then i generate the type after put the schema in my payload config

types gotten are not useable

export interface Media {
  id: number;
  alt: string;
  _key?: string | null;
  updatedAt: string;
  createdAt: string;
  url?: string | null;
  thumbnailURL?: string | null;
  filename?: string | null;
  mimeType?: string | null;
  filesize?: number | null;
  width?: number | null;
  height?: number | null;
  focalX?: number | null;
  focalY?: number | null;
}
/**
 * This interface was referenced by `Config`'s JSON-Schema
 * via the `definition` "case-studies".
 */
export interface CaseStudy {
  id: number;
  title: string;
  gallery?:
    | {
        **image: number | Media;**
        id?: string | null;
      }[]
    | null;
  link?: string | null;
  description?: string | null;
  updatedAt: string;
  createdAt: string;
}

then i make a request to my payload backend in the nextjs app ND i get this error

Type 'import("/workspace/port/src/payload-types").Testimonial[]' is not assignable to type 'Testimonial[]'.
  Type 'import("/workspace/port/src/payload-types").Testimonial' is not assignable to type 'Testimonial'.
    Types of property 'src' are incompatible.
      Type 'number | Media' is not assignable to type 'string'.
        Type 'number' is not assignable to type 'string'.ts(2322)
animated-testimonials.tsx(18, 3): The expected type comes from property 'testimonials' which is declared here on type 'IntrinsicAttributes & { testimonials: Testimonial[]; autoplay?: boolean | undefined; }'
(property) testimonials: Testimonial[]

Environment Info

Node: 20.17.0
  npm: 10.8.2
  Yarn: 1.22.22
  pnpm: 9.9.0
Relevant Packages:
  payload: 3.0.2
  next: 15.0.3
  @payloadcms/db-postgres: 3.0.2
  @payloadcms/email-nodemailer: 3.0.2
  @payloadcms/graphql: 3.0.2
  @payloadcms/next/utilities: 3.0.2
  @payloadcms/payload-cloud: 3.0.2
  @payloadcms/plugin-cloud-storage: 3.0.2
  @payloadcms/richtext-lexical: 3.0.2
  @payloadcms/storage-uploadthing: 3.0.2
  @payloadcms/translations: 3.0.2
  @payloadcms/ui/shared: 3.0.2
  react: 19.0.0-rc-64f89510-20241119
  react-dom: 19.0.0-rc-64f89510-20241119
Operating System:
  Platform: linux
  Arch: x64
  Version: #202407021948 SMP PREEMPT_DYNAMIC Tue Jul  2 20:28:47 UTC 2024
  Available memory (MB): 64298
  Available CPU cores: 16

firstaxel avatar Nov 27 '24 00:11 firstaxel

This issue has been marked as stale due to lack of activity.

To keep this issue open, please indicate that it is still relevant in a comment below.

github-actions[bot] avatar Dec 20 '24 05:12 github-actions[bot]

Please the issue hasn't been resolved

On Fri, Dec 20, 2024, 6:05 AM github-actions[bot] @.***> wrote:

This issue has been marked as stale due to lack of activity.

To keep this issue open, please indicate that it is still relevant in a comment below.

— Reply to this email directly, view it on GitHub https://github.com/payloadcms/payload/issues/9549#issuecomment-2556294749, or unsubscribe https://github.com/notifications/unsubscribe-auth/A5RGP2XVE7IT5HSNMGID6JL2GOQQBAVCNFSM6AAAAABSRTZ3VOVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDKNJWGI4TINZUHE . You are receiving this because you authored the thread.Message ID: @.***>

firstaxel avatar Dec 20 '24 08:12 firstaxel

I'm facing the same problem. The type for “uploads” is generated as number | Media; Payload 3.9.0

It seems to be due to the depth property, because with a value of 0, the id will be returned.

Kobreros avatar Dec 20 '24 13:12 Kobreros

Please can you fix this issue if you can tag them also

On Fri, Dec 20, 2024, 2:12 PM Michael @.***> wrote:

I'm facing the same problem. The type for “uploads” is generated as number | Media; Payload 3.9.0

— Reply to this email directly, view it on GitHub https://github.com/payloadcms/payload/issues/9549#issuecomment-2556978426, or unsubscribe https://github.com/notifications/unsubscribe-auth/A5RGP2U5DPT24QYDNLKJRSD2GQJUPAVCNFSM6AAAAABSRTZ3VOVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDKNJWHE3TQNBSGY . You are receiving this because you authored the thread.Message ID: @.***>

firstaxel avatar Dec 21 '24 08:12 firstaxel

Still happening on 3.20. I think it might be specific to when the postgres adapter is in use.

jpaas avatar Jan 31 '25 22:01 jpaas

Still happening on 3.20. I think it might be specific to when the postgres adapter is in use.

Confirmed. I tried the mongo adapter and it generated the correct types.

jpaas avatar Feb 03 '25 13:02 jpaas

So the issue now is the postgres adapter which we are using, is there any solution cause I have check the docs several times but I couldn't find way to alter the type definition of the type being generated. At least there should be a guide for that not just a small section

On Mon, Feb 3, 2025, 2:42 PM Julian Paas @.***> wrote:

Still happening on 3.20. I think it might be specific to when the postgres adapter is in use.

Confirmed. I tried the mongo adapter and it generated the correct types.

— Reply to this email directly, view it on GitHub https://github.com/payloadcms/payload/issues/9549#issuecomment-2631041993, or unsubscribe https://github.com/notifications/unsubscribe-auth/A5RGP2WLKDNJLZHXNCRG4H32N5W5DAVCNFSM6AAAAABSRTZ3VOVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDMMZRGA2DCOJZGM . You are receiving this because you authored the thread.Message ID: @.***>

firstaxel avatar Feb 03 '25 20:02 firstaxel

It's a pain in the ass, but it's not hard to work around. Any time you have a thing: number | Thing you just need to check if it's an id and then fetch the thing by its id.

const thing =
    typeof thingOrId === "object"
      ? thingOrId 
      : await payload.findByID({
          collection: "things",
          id: thingOrId ,
        });

EPurwanto avatar Feb 12 '25 02:02 EPurwanto

Yeah, this is rather annoying.

I'm doing this at the moment, feels a bit grubby

import type { ImageProps } from 'next/image'
import type { Media } from '~/payload-types'

export function parseImage(image: (number | null) | Media | undefined) {
	if (typeof image === 'number' || !image) return null

	return {
		src: image.url, // string | null | undefined
		width: image.width, // number | null | undefined
		height: image.height, // number | null | undefined
		alt: image.alt, // string | null | undefined
	} as ImageProps // eeeeee, this isn't ideal
}

it also means I have to do this every time i want to use an image, even though it's a required field

const image = parseImage(f.image)
return (
	<Carousel.Item
		value={0}
		key={f.id}
		className="w-full flex-shrink-0"
	>
		{image && <Image {...image} />}
		<Stack className="gap-7 text-center">
			<Text className="text-sm" weight="bold">
				{instruction}
			</Text>
			<Text className="text-5xl" weight="bold">
				{f.title}
			</Text>
		</Stack>
	</Carousel.Item>
)

magicspon avatar Feb 14 '25 14:02 magicspon

@magicspon i like this approach i just feel like it should be fixed in the future

firstaxel avatar Mar 06 '25 18:03 firstaxel

ping

drago1520 avatar May 28 '25 20:05 drago1520

2 things:

  1. Those types are correct
  2. You either get the ID (number | string *for uuid) or the Media object depending on access control and query depth

A helpful person wrote this on the official Discord - https://discord.com/channels/967097582721572934/1377390470958809128 This also explains the issue.

drago1520 avatar May 28 '25 21:05 drago1520

Yeah those types are correct. Based on depth and access control we cannot guarantee that the type will be fulfilled so it has to be ID | DocumentType. You can use one of the options in this thread to ensure the document is fully expanded for usage.

JarrodMFlesch avatar Jul 15 '25 19:07 JarrodMFlesch

This issue has been automatically locked. Please open a new issue if this issue persists with any additional detail.

github-actions[bot] avatar Jul 23 '25 05:07 github-actions[bot]