drizzle-orm icon indicating copy to clipboard operation
drizzle-orm copied to clipboard

[BUG]: TypeScript error on optional fields during update (and insert) operation

Open DavidHavl opened this issue 1 year ago • 19 comments

What version of drizzle-orm are you using?

0.32.0

What version of drizzle-kit are you using?

0.23.0

Describe the Bug

I've encountered a TypeScript error when trying to update an optional field using the set method. The error occurs only for optional fields, while required fields work as expected.

Steps to reproduce:

  • Define a table with both required and optional fields:
export const TasksTable = sqliteTable(
  'tasks',
  {
    id: text('id')
      .primaryKey()
      .$defaultFn(() => createId()),
    title: text('title').notNull(),
    description: text('description')
  },
);
  • Attempt to update the table with both required and optional fields:
const result = await db
  .update(TasksTable)
  .set({
    title: 'sdfg',
    description: 'asdf'
  });

Expected behavior: The update operation should work without any TypeScript errors, as all fields being updated are defined in the table schema.

Actual behavior: TypeScript throws an error for the optional 'description' field: "Object literal may only specify known properties, and 'description' does not exist in type" The error does not occur for the required 'title' field.

Additional notes:

  • The error only occurs for optional fields (those without .notNull())
  • Using as any type assertion works as a temporary workaround, but it's not a proper solution

Please let me know if you need any additional information or clarification to investigate this issue.

Expected behavior

The update operation should work without any TypeScript errors, as all fields being updated are defined in the table schema.

Environment & setup

Database: SQLite Node: 20 Typescript: 5.3.3

DavidHavl avatar Jul 18 '24 17:07 DavidHavl

We encountered this same issue with:

Database: Postgresql Node: 20 TypeScript: 5.5.3

We attempted to pin to a Drizzle ORM 0.31.0 to wait for a fix and discovered that we can't use Drizzle Kit if we do that. Drizzle Kit prints that it needs to be updated and won't generate migrations. The new version of Drizzle Kit requires Drizzle ORM > 0.32.0.

lmcneel avatar Jul 21 '24 01:07 lmcneel

Experiencing the same issue.

tirth0 avatar Jul 23 '24 12:07 tirth0

Same here

I suggest to use inferSelect instead of inferInsert, see below

export type PgUpdateSetSource<TTable extends PgTable> = { [Key in keyof TTable['$inferSelect']]?: GetColumnData<TTable['_']['columns'][Key]> | SQL; } & {};

Jean-CharlesTerrillon avatar Jul 24 '24 11:07 Jean-CharlesTerrillon

I was facing the same problem when upgrading to version >0.31.4, there's a post in discord where rphlmr said that you need strict mode on your tsconfig.json. That solved for me.

ps: I needed to remove all other strict tags and let only strict tag true.

murilo-kendjy avatar Jul 24 '24 11:07 murilo-kendjy

I was facing the same problem when upgrading to version >0.31.4, there's a post in discord where rphlmr said that you need strict mode on your tsconfig.json. That solved for me.

ps: I needed to remove all other strict tags and let only strict tag true.

While this does seem to fix the issue, I'd argue that this is an incredibly disruptive change to make to a project when it was not a requirement before now. Hopefully this can be resolved without resorting to flipping strict: true in projects that have been previously successfully using Drizzle without this compiler flag.

eliellis avatar Jul 24 '24 18:07 eliellis

same issue

mion-kr avatar Aug 01 '24 06:08 mion-kr

I have the same issue.

Environment:

  • OS: MacOS
  • Database: PostgreSQL
  • drizzle-orm version: 0.32.2
  • node version: v22.5.1
  • typescript version: 5.4.5

Temporary workaround: Add the following comment line above the insert command. // @ts-ignore: Unreachable code error

khanhquocnguyen avatar Aug 10 '24 13:08 khanhquocnguyen

Has there being any fix to this bug? I don't want to turn on strict mode in my tsconfig.json

Anuolu-2020 avatar Sep 02 '24 08:09 Anuolu-2020

Same issue please give me solution. any update to fix this issue ?

anishkumar127 avatar Sep 10 '24 08:09 anishkumar127

Any solution, I am also facing same issue?

sameedahri avatar Sep 18 '24 22:09 sameedahri

I found the solution guys. Just go to the tsconfig.json file, in the compiler options object add below line. "strictNullChecks": true,

sameedahri avatar Sep 22 '24 16:09 sameedahri

I found the solution guys. Just go to the tsconfig.json file, in the compiler options object add below line. "strictNullChecks": true,

this also not working!

anishkumar127 avatar Sep 23 '24 06:09 anishkumar127

Are you guys sure? Because I got stuck for so many days, and this thing solves the issue, I can also insert nullable values and typescript also auto complete table variable name

sameedahri avatar Sep 23 '24 10:09 sameedahri

Can you guys share you tsconfig file?

sameedahri avatar Sep 23 '24 10:09 sameedahri

Unfortunately, I decided not to upgrade the drizzle-orm and drizzle-kit packages since I don't want to change the typescript configs, which would cause a lot of other troubles in the project.

Here, I'm using drizzle-kit@^0.22.8 and drizzle-orm@^0.31.4.

leandromatos avatar Sep 24 '24 16:09 leandromatos

Changing it to strict worked for me to. (Postrgres and Drizzle-orm 0.33) I was confused because it was working just fine in another project but I had already turned strict on for Acktypes

jabreland avatar Sep 27 '24 01:09 jabreland

That's not a fix. I'm not going to rewrite a 20k LoC codebase to work with strict null checking just to make this work.

mogery avatar Sep 27 '24 11:09 mogery

The problem with using the strict option on TypeScript is that, depending on the size of your code base, you will be forced to update a lot of things. This is really annoying.

leandromatos avatar Sep 27 '24 13:09 leandromatos

I was going crazy after updating Drizzle to the latest version. Fortunately I've found that thread, maybe adding a notice in docs beside installation section would help users that were using Drizzle without ts strict mode.

naourass avatar Oct 03 '24 21:10 naourass

It seems to have gotten better with the 0.34 release. In our codebase we only have the issue remaining on the set parameter of the onConflictDoUpdate which can be easily worked around with a cast as Partial<typeof table.$inferInsert>🎉

lcptrs avatar Oct 08 '24 08:10 lcptrs

Unfortunately, @lcptrs, this workaround will add another problem. The result of an insert operation's inference returns the optional and required fields defined in the database. Your suggestion will make all the properties optional.

I believe this problem won't be fixed in the near future. It seems to be a mix of the natural evolution of TypeScript and its config and the evolution of other dependencies. I'm not sure about that, but if the solution is to use strict: true on the tsconfig.json, I think it is because some dependencies use the strict property, and the types are conflicting.

I will probably give up and put strict: true on my project, fix all the TypeScript problems caused by this config, and finally update the new versions of the Drizzle packages.

leandromatos avatar Oct 09 '24 21:10 leandromatos

is there any update on this? still not fixed.

database: postgres node: 20 typescript: 5.6.3 drizzle-orm: 0.36.1 drizzle-kit: 0.28.0

ghost avatar Nov 11 '24 18:11 ghost

same problem :(

drizzle-orm: 0.36.1 drizzle-kit: 0.28.0

NiazMorshed2007 avatar Nov 12 '24 05:11 NiazMorshed2007

well, that's a very tricky one, we've spent half a day with @Sukairo-02 trying to figure out what type in particular is responsible for that

strict: true indeed fixes it, with strict: false there're 2 more ts flags that fix it, yet we will make sure it works out of the box for you

AlexBlokh avatar Nov 12 '24 20:11 AlexBlokh

alright, landing in beta today - https://github.com/drizzle-team/drizzle-orm/pull/3542

AlexBlokh avatar Nov 13 '24 14:11 AlexBlokh

faced the issue today, love to see that the fix has been merged in beta :rocket:

ahsankhan201010 avatar Nov 14 '24 09:11 ahsankhan201010

fixed in [email protected]

AndriiSherman avatar Nov 14 '24 12:11 AndriiSherman

Still facing the issue and have to use // @ts-ignore: Unreachable code error or something like as Partial<typeof table.$inferUpdate>. Setting "strictNullChecks": true, or removing it raises too many errors across the code that need to be fixed or ignored by the compiler. Really enjoying Drizzle ORM, but have to say it is very wonky at times.

Below is additional information of my file, method and schema structures.

❗ Notice that my field cartItemStatus is not even an optional field as others in this thread mention but it still causes the problem.

package.json

{
  "name": "fitbyprince",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "next lint"
  },
  "dependencies": {
    "@emotion/cache": "^11.13.1",
    "@emotion/react": "^11.13.0",
    "@emotion/styled": "^11.13.0",
    "@mui/icons-material": "^5.16.7",
    "@mui/lab": "6.0.0-beta.14",
    "@mui/material": "^5.16.7",
    "@mui/material-nextjs": "^5.16.6",
    "@stripe/react-stripe-js": "^2.8.1",
    "@stripe/stripe-js": "^4.9.0",
    "@supabase/ssr": "^0.5.1",
    "@types/luxon": "^3.4.2",
    "@vercel/functions": "^1.4.1",
    "@vidstack/react": "^1.12.11",
    "dotenv": "^16.4.5",
    "drizzle-orm": "^0.36.4",
    "embla-carousel": "^8.1.8",
    "embla-carousel-react": "^8.1.8",
    "embla-carousel-wheel-gestures": "^8.0.1",
    "luxon": "^3.5.0",
    "next": "14.2.5",
    "postgres": "^3.4.4",
    "react": "^18",
    "react-dom": "^18",
    "stripe": "^17.3.1",
    "use-debounce": "^10.0.3"
  },
  "devDependencies": {
    "@types/node": "^20",
    "@types/react": "^18",
    "@types/react-dom": "^18",
    "drizzle-kit": "^0.24.2",
    "eslint": "^8",
    "eslint-config-next": "14.2.5",
    "postcss": "^8",
    "tailwindcss": "^3.4.1",
    "typescript": "^5"
  }
}

tsconfig.json

{
  "compilerOptions": {
    "lib": ["dom", "dom.iterable", "esnext"],
    "allowJs": true,
    "skipLibCheck": true,
    "strict": true,
    "strictNullChecks": false,
    "noEmit": true,
    "esModuleInterop": true,
    "module": "esnext",
    "moduleResolution": "bundler",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "jsx": "preserve",
    "incremental": true,
    "plugins": [
      {
        "name": "next"
      }
    ],
    "paths": {
      "@/*": ["./src/*"],
      "@/app/*": ["./src/app/*"],
      "@/enums/*": ["./src/lib/enums/*"],
      "@/interfaces/*": ["./src/libs/interfaces/*"],
      "@/types/*": ["./src/libs/types/*"],
      "@/utils/*": ["./src/libs/utils/*"],
      "@/ui/*": ["./src/libs/ui/*"],
      "@/styles/*": ["./src/libs/styles/*"],
      "@/server/*": ["./src/libs/server/*"],
      "@/client/*": ["./src/libs/client/*"],
      "@/drizzle/*": ["./src/libs/server/drizzle/*"],
      "@/supabase/*": ["./src/libs/server/supabase/index.ts"],
      "@/actions/*": ["./src/libs/server/actions/*"],
      "@/libs/*": ["./src/libs/*"]
    }
  },
  "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
  "exclude": ["node_modules"]
}

Drizzle Schema

// CartItem Table
export const cartItems = pgTable("cartItems", {
  ...baseSchema,
  ...timestampedSchema,
  itemId: uuid("itemId").notNull(),
  quantity: integer("quantity").notNull().default(1),
  productType: productTypesEnum("productType").notNull(),
  profileId: uuid("profileId")
    .notNull()
    .references(() => profiles.id, { onDelete: "cascade" }),
  cartItemStatus: cartItemStatusesEnum("cartItemStatus")
    .notNull()
    .default("PENDING"),
});

My method

  async updateCartItemsStatusByProfileId(params: { profileId: string, newCartItemStatus: CartItemStatus, options?: { cartItemStatus?: CartItemStatus } }): Promise<CartItemsUpdate> {
    const { profileId, newCartItemStatus, options } = params;

    // NOTE: Temporary fix for false fix at -> https://github.com/drizzle-team/drizzle-orm/issues/2654#issuecomment-2475787921
    // @ts-ignore: Unreachable code error
    const query = db.update(cartItems).set({ cartItemStatus: newCartItemStatus });

    if (options?.cartItemStatus) {
      query.where(eq(cartItems.cartItemStatus, options?.cartItemStatus));
    }

    query.where(eq(cartItems.profileId, profileId));

    return await query;

  }

Said-Alisic avatar Nov 24 '24 16:11 Said-Alisic

I'm experiencing the same here, @Said-Alisic 😢

leandromatos avatar Nov 25 '24 18:11 leandromatos

I'm also facing the same issue: when using insert, it doesn't recognize optional fields.

 "drizzle-orm": "^0.36.4"

andyngdz avatar Nov 30 '24 08:11 andyngdz