#Only plain objects can be passed to Client Components from Server Components. Decimal objects not

106 messages · Page 1 of 1 (latest)

sick umbra
lean abyssBOT
#

🔎 This post has been indexed in our web forum and will be seen by search engines so other users can find it outside Discord

🕵️ Your user profile is private by default and won't be visible to users outside Discord, if you want to be visible in the web forum you can add the "Public Profile" role in id:customize

✅ You can mark a message as the answer for your post with Right click -> Apps -> Mark Solution
(if you don't see the option, try refreshing Discord with Ctrl + R)

sick umbra
#

I have a products form where i can edit or add a new product.

When I want to go a single product page to edit it, i get this warning in console:

  {id: ..., storeId: ..., categoryId: ..., name: ..., price: Decimal, isFeatured: ..., isArchived: ..., sizeId: ..., colorId: ..., createdAt: ..., updatedAt: ..., images: ...}```
#

Product page is:

import ProductsForm from "@/components/products-form";
import {
  getCategories,
  getColors,
  getProductWithOnlyImagesRelation,
  getSizes,
} from "@/server/data-access-layer";

export default async function ProductPage({
  params,
}: {
  params: { productId: string; storeId: string };
}) {
  const product = await getProductWithOnlyImagesRelation(params.productId);

  const formattedProduct = {
    ...product,
    price: product?.price.toNumber(),
  };

  const categories = await getCategories(params.storeId);

  const sizes = await getSizes(params.storeId);

  const colors = await getColors(params.storeId);
  return (
    <div className="flex-col">
      <div className="flex-1 space-y-4 p-8 pt-6">
        <ProductsForm
          categories={categories}
          colors={colors}
          sizes={sizes}
          initialData={formattedProduct}
        />
      </div>
    </div>
  );
}
#

Is there a better way than formatting the product and attaching it in the initialData prop instead of the normal product?

#

If I use formattedProduct instead, I get this from initial data prop:

#
  Type '{ price: number | undefined; images?: { id: string; productId: string; url: string; createdAt: Date; updatedAt: Date; }[] | undefined; id?: string | undefined; storeId?: string | undefined; ... 7 more ...; updatedAt?: Date | undefined; }' is not assignable to type '{ id: string; storeId: string; categoryId: string; name: string; price: Decimal; isFeatured: boolean; isArchived: boolean; sizeId: string; colorId: string; createdAt: Date; updatedAt: Date; }'.
    Types of property 'id' are incompatible.
      Type 'string | undefined' is not assignable to type 'string'.
        Type 'undefined' is not assignable to type 'string'.ts(2322)
types.ts(169, 3): The expected type comes from property 'initialData' which is declared here on type 'IntrinsicAttributes & ProductFormProps'```
sick umbra
#

bump

sick umbra
#

bump

sick umbra
#

bump

sick umbra
#

bump

sick umbra
#

bump

sick umbra
#

bump

safe nymph
#

wow props for following the rules ngl

#

cant you just use Numbers instead of.. Decimal?

#

Or if you need to use Decimal, the issue is that Decimals cant be serialized in js atm

#

so pass it as a string to the client component
decimalValue.toString()

#

then you can convert back like this
const decimal = new Decimal(decimalAsString);

#

@sick umbra

sick umbra
#
import ProductsForm from "@/components/products-form";
import {
  getCategories,
  getColors,
  getProductWithOnlyImagesRelation,
  getSizes,
} from "@/server/data-access-layer";

export default async function ProductPage({
  params,
}: {
  params: { productId: string; storeId: string };
}) {
  const product = await getProductWithOnlyImagesRelation(params.productId);

  const formattedProduct = {
    ...product,
    price: product?.price.toNumber(),
  };

  const categories = await getCategories(params.storeId);

  const sizes = await getSizes(params.storeId);

  const colors = await getColors(params.storeId);
  return (
    <div className="flex-col">
      <div className="flex-1 space-y-4 p-8 pt-6">
        <ProductsForm
          categories={categories}
          colors={colors}
          sizes={sizes}
          initialData={formattedProduct}
        />
      </div>
    </div>
  );
}

safe nymph
#

oh

sick umbra
#

to number or can also do string as u said since those can be passed to client components

#

but

safe nymph
#

Warning: Only plain objects can be passed to Client Components from Server Components. Decimal objects are not supported.

You dont see this anymore then right?

sick umbra
#

yes i have problem with the types now

#

if i hover over initialData prop

#

Type '{ price: number | undefined; images?: { id: string; productId: string; url: string; createdAt: Date; updatedAt: Date; }[] | undefined; id?: string | undefined; storeId?: string | undefined; ... 7 more ...; updatedAt?: Date | undefined; }' is not assignable to type '{ id: string; storeId: string; categoryId: string; name: string; price: Decimal; isFeatured: boolean; isArchived: boolean; sizeId: string; colorId: string; createdAt: Date; updatedAt: Date; } & { ...; }'.
Type '{ price: number | undefined; images?: { id: string; productId: string; url: string; createdAt: Date; updatedAt: Date; }[] | undefined; id?: string | undefined; storeId?: string | undefined; ... 7 more ...; updatedAt?: Date | undefined; }' is not assignable to type '{ id: string; storeId: string; categoryId: string; name: string; price: Decimal; isFeatured: boolean; isArchived: boolean; sizeId: string; colorId: string; createdAt: Date; updatedAt: Date; }'.
Types of property 'id' are incompatible.
Type 'string | undefined' is not assignable to type 'string'.
Type 'undefined' is not assignable to type 'string'.ts(2322)
types.ts(169, 3): The expected type comes from property 'initialData' which is declared here on type 'IntrinsicAttributes & ProductFormProps'

#

and if i hover over initial data, it will show like this:

safe nymph
#

show me <ProductsForm>

sick umbra
#

(property) initialData: ({
id: string;
storeId: string;
categoryId: string;
name: string;
price: Decimal;
isFeatured: boolean;
isArchived: boolean;
sizeId: string;
colorId: string;
createdAt: Date;
updatedAt: Date;
} & {
...;
}) | null

#

this is Products form

#

types are:

#
export type ProductFormProps = {
  initialData: (Product & { images: Image[] }) | null;
  categories: Category[];
  colors: Color[];
  sizes: Size[];
};
#

and my product model

#
model Product {
  id String @id @default (uuid())
  storeId String
  store Store @relation("StoreToProduct", fields: [storeId], references: [id])
  categoryId String
  category Category @relation("CategoryToProduct", fields: [categoryId], references: [id])
  name String
  price Decimal
  isFeatured Boolean @default(false)
  isArchived Boolean @default(false)
  sizeId String
  size Size @relation(fields: [sizeId],references: [id])
  colorId String
  color Color @relation(fields: [colorId], references: [id])
  images Image[]
  orderItems OrderItem[]
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt

  @@index([storeId])
  @@index([categoryId])
  @@index([sizeId])
  @@index([colorId])
}
safe nymph
#

chill

#

lol

sick umbra
#

in case ur next questions would be how props look lol

safe nymph
#

its an easy fix, so basically

#

const product = await getProductWithOnlyImagesRelation(params.productId);

#

hover over product

#

and tell me what you see for the type of id

sick umbra
#

string

#

or u mean type of price?

safe nymph
#

just string or string | undefined

sick umbra
#

just string

#

const product: ({
images: {
id: string;
productId: string;
url: string;
createdAt: Date;
updatedAt: Date;
}[];
} & {
id: string;
storeId: string;
categoryId: string;
name: string;
price: Decimal;
isFeatured: boolean;
isArchived: boolean;
sizeId: string;
colorId: string;
createdAt: Date;
updatedAt: Date;
}) | null

#

thats how it looks

safe nymph
#

createdAt: Date; updatedAt: Date; }'.
Types of property 'id' are incompatible.
Type 'string | undefined' is not assignable to type 'string'.
Type 'undefined' is not assignable to type 'string'.ts(2322)

#

one of your ids are undefined

#

real quick, paste this

#
  const formattedProduct = {
    ...product,
    id: product?.id ?? "",
    price: product?.price.toNumber(),
  };
sick umbra
#

now it continues to the next one

#

Types of property 'storeId' are incompatible.
Type 'string | undefined' is not assignable to type 'string'.
Type 'undefined' is not assignable to type 'string'.ts(2322)

safe nymph
#

but see the issue now?

#

cause like

#

product

#

can be null

#

got that right @sick umbra

sick umbra
#

yes

safe nymph
#

now null isnt an object, it dosent have properties. hence why null.id is undefined
you need to add a like checker for it.

sick umbra
#

if there is initial data then it will use initial data

#

but it can be null

safe nymph
#

mhm

sick umbra
safe nymph
#

yes.

sick umbra
#

like i have price/id, but do for all

safe nymph
#

yes.

#

id: product?.id ?? "",

#

if the id exists, its gonna use it.. if its undefined.. it will use ""

sick umbra
#

ok, let me do this and get back to u

safe nymph
#

sure

#

this is why we love typescript ❤️

sick umbra
#

@safe nymph ok now i got this

#

Types of property 'price' are incompatible.
Type 'number' is not assignable to type 'Decimal'.ts(2322)

#

const formattedProduct = {
...product,
id: product?.id ?? "",
storeId: product?.storeId ?? "",
categoryId: product?.categoryId ?? "",
name: product?.name ?? "",
price: product?.price.toNumber() ?? 0,
};

safe nymph
#

price: Decimal;

#

price: product?.price.toNumber(),

#

see the issue? :D

sick umbra
#

if im understanding right, im passing a number, but my product form props are using the ProductFormProps types

#

and initial data type is made of Product model which has price: decimal

#

so im not sure to go around this, since i want to keep decimal in my model

safe nymph
#

make initial data accept a Number

#

then convert it back to Decimal

#

once you are in the client component

sick umbra
#

initialData: (Product & { images: Image[] }) | null;

#

@safe nymph u mean this one right?

#

and instead of "Product" ill just write the fields myself

#

and have the price be number not decimal

safe nymph
#

yea

sick umbra
#

@safe nymph when it comes to type Date

#

what would the empty value be here?

#

as in, for strings its ""

#

but what is it for a Date type?

#

new Date(0) to set it to unix epoch or new Date() ?

safe nymph
#

Set Dates to strings by .getTime()

#

It will return back in ms

#

As a string

sick umbra
#

@safe nymph like this? createdAt: product?.createdAt.getTime().toString() ?? "",

#

because they will still be incompatible

sick umbra
#

actually found much easier way:D instead of accounting for all the variables, i just conditionally format my product only if i already have some data in it

#
const formattedProduct = product
    ? {
        ...product,
        price: product?.price.toNumber() ?? 0,
      }
    : null;
#

thanks for all ur help nonetheless

safe nymph
#

Sure, make your types as needed