Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Typechecking doesn't work when insert value is instantiated outside the values function #641

Closed
maktouch opened this issue Aug 8, 2023 · 6 comments
Labels
bug Something isn't working typescript Related to Typescript wontfix This will not be worked on

Comments

@maktouch
Copy link
Contributor

maktouch commented Aug 8, 2023

In this playground link: https://kysely.dev/docs/examples/INSERT/single-row

const result = await db
  .insertInto('person')
  .values({
    first_name: 'Jennifer',
    last_name: 'Aniston',
    age: 40,
    hello: 'world'
  })
  .executeTakeFirst()

console.log(result.insertId)

This gets correctly typechecked. Column hello doesn't exist and there's squiggly lines everywhere.
This, however, doesn't work.

const obj = {
    first_name: 'Jennifer',
    last_name: 'Aniston',
    age: 40,
    hello: 'world'
  }
  
const result = await db
  .insertInto('person')
  .values(obj)
  .executeTakeFirst()

console.log(result.insertId)

Same thing for updates.

This is quite a footgun!

@igalklebanov
Copy link
Member

Hey 👋

This is a general TypeScript problem. I'll try to find the relevant issue/s later.
You can find the same shenanigans in anything that involves objects, see zod's pick/omit methods.

Lemme give you another weird behavior:

const values = {
    first_name: 'Jennifer',
    last_name: 'Aniston',
    age: 40,
    hello: 'world'
}

const result = await db
  .insertInto('person')
  .values([values, {
    first_name: 'Jennifer',
    last_name: 'Aniston',
    age: 40,
    hello: 'world'
  }])
  .executeTakeFirst()

no type errors.

const values = {
    first_name: 'Jennifer',
    last_name: 'Aniston',
    age: 40,
    hello: 'world'
  }

const result = await db
  .insertInto('person')
  .values([{
    first_name: 'Jennifer',
    last_name: 'Aniston',
    age: 40,
    hello: 'world'
  }, values])
  .executeTakeFirst()

again, no type-errors.

if you add as const to values, there are type-errors.
so you should always use as const when passing input "from outside" in type-safe TS libraries.

I actually had a PR that "fixes" it with a hack, but we rightfully didn't merge it as it's unhealthy. This is TypeScript's responsibility to fix.
#229

@igalklebanov igalklebanov added bug Something isn't working wontfix This will not be worked on typescript Related to Typescript labels Aug 8, 2023
@maktouch
Copy link
Contributor Author

maktouch commented Aug 8, 2023

hmm but even with as const it doesn't work?

const obj = {
    first_name: 'Jennifer',
    last_name: 'Aniston',
    age: 40,
    hello: 'world'
  } as const

const result = await db
  .insertInto('person')
  .values(obj)
  .executeTakeFirst()

console.log(result.insertId)

@igalklebanov
Copy link
Member

igalklebanov commented Aug 8, 2023

It worked on the 2 item example, haven't checked on single value example.

Here's some related text from people who are more in the know about this issue.
https://stackoverflow.com/a/57015227
microsoft/TypeScript#12936
microsoft/TypeScript#13444 (comment)

@cmmartin
Copy link

cmmartin commented Aug 8, 2023

Okay, so typescript allows additional members, which makes sense. What doesn't make sense is why this is valid...

const obj = {
    first_name: 'Jennifer',
    last_name: 'Aniston',
    age: 40,
    hello: 'world'
  }
  
const result = await db
  .insertInto('person')
  .values(obj)
  .executeTakeFirst()

but this is not...

const result = await db
  .insertInto('person')
  .values({
    first_name: 'Jennifer',
    last_name: 'Aniston',
    age: 40,
    hello: 'world'
  })
  .executeTakeFirst()

If the explanation is that the additional members are not type errors, then both of these should be valid. Something else is going on here

@igalklebanov
Copy link
Member

igalklebanov commented Aug 9, 2023

What can you do, when one of TypeScript's team says: "works as intended". 🤷

  1. You could do some type hackery but, it's unhealthy, hurts compile-time performance, makes the code less readable, and might break with any new TypeScript version.
  2. Wait. This is TypeScript's responsibility to fix. They haven't closed the exact types issue, so there's hope.
  3. Spread awareness of this TypeScript caveat and provide recommendations in documentation.
  4. Provide an alternative API that doesn't use objects as inputs.

@maktouch
Copy link
Contributor Author

maktouch commented Aug 9, 2023

I think 3. Spread awareness of this TypeScript caveat and provide recommendations in documentation. makes the most sense. I'll try to make PR for the docs in the coming days.

Thanks for everything!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working typescript Related to Typescript wontfix This will not be worked on
Projects
None yet
Development

No branches or pull requests

3 participants