Skip to content
New issue

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

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

Already on GitHub? # to your account

WithFieldValue mangles Class Types #2291

Open
7 tasks done
rgant opened this issue Feb 12, 2025 · 15 comments · May be fixed by #2294
Open
7 tasks done

WithFieldValue mangles Class Types #2291

rgant opened this issue Feb 12, 2025 · 15 comments · May be fixed by #2294
Assignees
Labels
api: firestore Issues related to the googleapis/nodejs-firestore API.

Comments

@rgant
Copy link

rgant commented Feb 12, 2025

Please make sure you have searched for information in the following guides.

A screenshot that you have tested with "Try this API".

Attempting to use WithFieldValue<Date> mangles to Date type such that tsc no longer recognizes it as a Date. I assume this happens for most other non-primitive values in Firestore documents.

   63:37  error   Argument of type 'FieldValue | WithFieldValue<Date>' is not assignable to parameter of type 'Date | FieldValue'. ​typescript(2345)
                    Type '{ toString: FieldValue | WithFieldValue<() => string>; toDateString: FieldValue | WithFieldValue<() => string>; toTimeString: FieldValue | WithFieldValue<...>; ... 41 more ...; [Symbol.toPrimitive]: FieldValue | WithFieldValue<...>; }' is not assignable to type 'Date | FieldValue'.
                      Type '{ toString: FieldValue | WithFieldValue<() => string>; toDateString: FieldValue | WithFieldValue<() => string>; toTimeString: FieldValue | WithFieldValue<...>; ... 41 more ...; [Symbol.toPrimitive]: FieldValue | WithFieldValue<...>; }' is not assignable to type 'Date'.
                        Types of property 'toString' are incompatible.
                          Type 'FieldValue | WithFieldValue<() => string>' is not assignable to type '() => string'.
                            Type 'FieldValue' is not assignable to type '() => string'.
                              Type 'FieldValue' provides no match for the signature '(): string'.

Link to repro. A link to a public Github Repository or gist with a minimal reproduction.

https://github.com/rgant/brainfry

https://gist.github.com/rgant/adf3984ebd43c278b716c372412f7109/193be3d9e79f8beafc452a2c814af61883ea9958

A step-by-step description of how to reproduce the issue, based on the linked reproduction.

This all happens when running linters and type checkers in my editor.

A clear and concise description of what the bug is, and what you expected to happen.

Because WithFieldValue<Post> climbs inside of the Date property this results problems with typing as seen on line 63

I can fix this (with some ugly unnecessary code my throwing a TypeError if the parameter isn't a Date nor a FieldValue.

A clear and concise description WHY you expect this behavior, i.e., was it a recent change, there is documentation that points to this behavior, etc. **

I feel like the documentation update is better, but doesn't actually cover a real world case. Maybe I'm just strange but I wouldn't use a number of milliseconds in a front end application where I expect to display a date and time of a post. I would use a JavaScript Date (or Temporal).

@product-auto-label product-auto-label bot added the api: firestore Issues related to the googleapis/nodejs-firestore API. label Feb 12, 2025
Copy link

Issue was opened with an invalid reproduction link. Please make sure the repository is a valid, publicly-accessible github repository, and make sure the url is complete (example: https://github.com/googleapis/google-cloud-node)

@rgant
Copy link
Author

rgant commented Feb 12, 2025

If interested I can open a PR to update the documentation with my fixes. However, it really does feel like WithFieldValue (and PartialWithFieldValue) are not correct and should be fixed.

@rgant
Copy link
Author

rgant commented Feb 12, 2025

Issue was opened with an invalid reproduction link. Please make sure the repository is a valid, publicly-accessible github repository, and make sure the url is complete (example: https://github.com/googleapis/google-cloud-node)

Link should be good now. Hard to manage multiple revisions in a gist.

@milaGGL
Copy link
Contributor

milaGGL commented Feb 13, 2025

Hi @rgant, thank you for raising this issue. As you noticed, T is passed down only if it is a primitive data type, otherwise, it needs to wrap it with WithFieldValue as in your fix.

@rgant
Copy link
Author

rgant commented Feb 13, 2025

But then TypeScript doesn't understand that date instanceof Date is a type guard for WithFieldValue<Date> which since it is just a type doesn't have a way to type guard that I know of.

If WithFieldValue cannot be changed to not mangle standard Objects, then should the documentation be updated with a more real world example that documents this typical experience?

@MarkDuckworth
Copy link
Contributor

seems like the bot incorrectly closed this issue

@MarkDuckworth MarkDuckworth reopened this Feb 14, 2025
@MarkDuckworth MarkDuckworth self-assigned this Feb 14, 2025
Copy link

Issue was opened with an invalid reproduction link. Please make sure the repository is a valid, publicly-accessible github repository, and make sure the url is complete (example: https://github.com/googleapis/google-cloud-node)

Copy link

Issue was opened with an invalid reproduction link. Please make sure the repository is a valid, publicly-accessible github repository, and make sure the url is complete (example: https://github.com/googleapis/google-cloud-node)

@rgant
Copy link
Author

rgant commented Feb 14, 2025

I tried adding another link to a repo to make the bot happy hopefully.

@MarkDuckworth
Copy link
Contributor

MarkDuckworth commented Feb 14, 2025

@rgant, This is an interesting issue. If I understand, the general request is that the type WithFieldValue<T> will stop traversing into certain object types. In the example below you (or another user) might want it to traverse into Author, but not Date.

type Post = {
  title: string;
  author: Author;
  lastUpdated: Date;
}

type Author = {
  name: string;
}

type T = WithFieldValue<Post>;

I'm not aware of how WithFieldValue<T> could be that selective.

The runtime check d instanceof Date may your best solution for now.

@MarkDuckworth MarkDuckworth reopened this Feb 14, 2025
Copy link

Issue was opened with an invalid reproduction link. Please make sure the repository is a valid, publicly-accessible github repository, and make sure the url is complete (example: https://github.com/googleapis/google-cloud-node)

@rgant
Copy link
Author

rgant commented Feb 14, 2025

I think there are relatively few types that can both appear in a Firestore document and payload without erring.

Could we add Date | Timestamp to the Primitive type?

export type Primitive = string | number | boolean | undefined | null;

Or add some sort of "Classy" type like declare type Class<T = any> = new (...args: any[]) => T;

@MarkDuckworth
Copy link
Contributor

Updated the description to stop the auto-close for "invalid link"

@MarkDuckworth MarkDuckworth reopened this Feb 14, 2025
@MarkDuckworth
Copy link
Contributor

I think there are relatively few types that can both appear in a Firestore document and payload without erring

I'm not sure if I understand. The type(s) passed to the converter (e.g. Post, Date, Author...) may or may not be converted to some other object that is written to the DB. Limiting the solution to Date and Timestamp, doesn't seem like a general solution. Interesting idea too about the "Classy" type, but I think that would make it ignore Author and Class, if they were defined as a class and not a type.

I may be able to tweak WithFieldValue to ignore any functions, which would address the issue you're experiencing with Date, and also be a general improvement, I think.

@rgant
Copy link
Author

rgant commented Feb 14, 2025

It is my belief that WithFieldValue exists to allow you do do things like serverTimestamp() and arrayUnion(). Since post.author = FieldValue.delete() is a valid construct I don't have a problem that WithFieldValue applies to it.

What I think is wrong is post.lastUpdated.toJson = FieldValue.delete() since that is never a correct. So it sounds like ignoring functions would solve part of the problem.

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
api: firestore Issues related to the googleapis/nodejs-firestore API.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants