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

How to use instanceof to class with private constructor #384

Closed
YutaUra opened this issue Apr 6, 2021 · 3 comments
Closed

How to use instanceof to class with private constructor #384

YutaUra opened this issue Apr 6, 2021 · 3 comments

Comments

@YutaUra
Copy link

YutaUra commented Apr 6, 2021

first, I want to use zod with firebase/firestore. And there is FieldValue class use for createdAt or updatedAt.

So, I think like this to use zod with firebase

import * as z from 'zod'
import firebase from 'firebase/app'

const ServerTimestampSchema = z.instanceof(firebase.firestore.FieldValue)

const UserSchema = z.object({
  name: z.string(),
  // ...
  createdAt: ServerTimestampSchema,
  updatedAt: ServerTimestampSchema
})

maybe, this works at run time, but typescript compiler throw this message.

// ...
const ServerTimestampSchema = z.instanceof(firebase.firestore.FieldValue)
// Argument of type 'typeof FieldValue' is not assignable to parameter of type 'new (...args: any[]) => any'.
//  Cannot assign a 'private' constructor type to a 'public' constructor type.ts(2345)

// ...

If someone has any solutions, please tell me!!

@colinhacks
Copy link
Owner

Hm, interesting problem. Based on a quick review, it doesn't appear to be solvable inside of instanceof. The only way for Zod to infer the type of the class passed into z.instanceof is to constrain it to the form new (...args: any[]) => any and use the InstanceType utility: https://www.typescriptlang.org/docs/handbook/utility-types.html#instancetypetype.

However, in your particular case you can easily build your own using z.custom, which was introduced specifically for things like this. It accepts an explicit type and lets you specify a custom refinement check (in this case, an instanceof check). Here's the code:

const ServerTimestampSchema = z.custom<firebase.firestore.FieldValue>(
  (data) => data instanceof firebase.firestore.FieldValue
);

@ScreamZ
Copy link

ScreamZ commented Jun 22, 2023

For those like me trying to validate a luxon Duration this « hack » is valid.

import { z } from "zod";
import { Duration } from "luxon";

const IntervalValidator = z.custom<Duration>((t) => t instanceof Duration);

@sweetcoco
Copy link

Here are schemas for common Firestore FieldValue and Timestamp cases:

import { FieldValue, Timestamp } from "firebase-admin/firestore";
import { z } from "zod";

// this is a Timestamp from the database
export const TimestampSchema = z.custom<Timestamp>(
  (data) => data instanceof Timestamp
);

// this is a FieldValue instance, to be written to the database
export const FieldValueSchema = z.custom<FieldValue>(
  (data) => data instanceof FieldValue
);

// this is a FieldValue, specifcally ServerTimestampTransform, to be written to the database
export const FieldValueServerTimestampSchema = z.custom<any>(
  (data) => (data as Object).constructor.name === FieldValue.serverTimestamp().constructor.name
);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants