kossnocorp / typesaurus

🦕 Type-safe TypeScript-first ODM for Firestore
https://typesaurus.com
415 stars 35 forks source link

Weird type-safety behaviour when using $ helper #132

Open Ivanrenes opened 6 months ago

Ivanrenes commented 6 months ago

Hey I'm having an issue with type safety when using $ helper.

Seems like when using $ helper, we lost full type safety since TS does not complain about "inexistentProp". image

However if we remove the $ helper, it works as expected, triggering "inexistentProp" as not part of type User image

Versions tested:

If need more context lmk!

kossnocorp commented 6 months ago

Hey! Thank you for opening the issue. Here's what's going on:

The problem is that TypeScript has structured typing, and there's no way to fix it without making the developer experience slightly worse.

Here's a playground link with the gist of the problem.

And here's one of many TypeScripts related to it: https://github.com/microsoft/TypeScript/issues/12936

TL;DR: TypeScript can't do it.

However, I found a solution that works, but as I said, it makes the experience slightly worse. I can't ship it with the v10 as it will be a breaking change, and also, I'm hesitant to introduce it as it will break so much code even though the user-code fix would be pretty trivial 😞

So here's what I did in Superstate, my other type-safe project:

form.send.submit("error", "-> errored", ($, context) =>
  $({ ...context, error: "Email is missing" })
);

Instead of returning an object, it forces to wrap it into an argument. It triggers an extra properties check that is missing from the function return but present on argument passing.

So, in Typesaurus, it would look like this:

await db.users.add(($) => $({
  name: "Sasha",
  createdAt: $.serverDate(),
  inexistentProp: ''
  //^^^^^^^^^^^^
  // Type error
}));

I think it's worth it, but as I said, it will require a breaking change, and I wanted to keep v10 stable for a long time. I could use a schema function option to switch types used for the write helpers, but I'm unsure how much work it would be and if it's worth the sacrifice to preserve v10 stability.

What do you think? I would appreciate any feedback.