zod icon indicating copy to clipboard operation
zod copied to clipboard

`z.instanceof` does not accept abstract classes

Open WillsterJohnson opened this issue 1 year ago • 1 comments

In #1065, z.instanceof rejects classes with a private constructor. This can be resolved by using z.custom, but this syntax isn't ideal and repeats itself between the type param and the right hand side of instanceof operator.

A similar issue appears when using an abstract class, is there anything that could be done about that?

abstract class foo {
  constructor() {}
}

z.instanceof(foo);
// Argument of type 'typeof foo' is not assignable to parameter of type 'new (...args: any[]) => any'.
//  Cannot assign an abstract constructor type to a non-abstract constructor type. ts(2345)

This can be worked around using the above, but typescript does allow for parameter type abstract new (...args: any[]) => any, which could be used either in place of or in union to the existing parameter type on z.instanceof

Failing that, a class is just a different syntax for defining a function, and classes can be passed to parameter type Function. This allows for incorrect usage by passing a normal, non-class function, but I expect most users of Zod to understand the difference on the basis of a) they're competent enough to be using TypeScript and b) they're using Zod, a schema-base parser/validator.

// this has no issues with very strict TS compiler options
function parse(x: Function, y: unknown) {
  return y instanceof x;
}

// this solves the abstract issue, and prevents passing incorrect subtypes of `Function`

/** this union is not necessary and will work with only the abstract variant. The union is to be more verbose */
type MaybeAbstractClass = (abstract new (...args: any[]) => any) | (new (...args: any[]) => any);

function parse(x: MaybeAbstractClass, y: unknown) {
  return y instanceof x;
}

WillsterJohnson avatar Aug 14 '22 18:08 WillsterJohnson

I found a fix for this but it requires bumping the minimum version to TS4.4 which I'd rather avoid until I release another major version.

colinhacks avatar Sep 06 '22 08:09 colinhacks

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

stale[bot] avatar Nov 05 '22 14:11 stale[bot]