ajv icon indicating copy to clipboard operation
ajv copied to clipboard

JSONSchemaType allows schemas with optional attributes for Types where they are required

Open slifty opened this issue 3 years ago • 3 comments

What version of Ajv are you using? Does the issue happen if you use the latest version? Using 8.11.0 (latest)

Ajv options object

No options are set

export const ajv = new Ajv();

JSON Schema

interface MyExample {
  foo: number;
}
const myExampleSchema: JSONSchemaType<MyExample> = {
  type: 'object',
  properties: {
    foo: {
      type: 'number',
      nullable: true,
    },
  },
  required: [],
}

Validation result, data AFTER validation, error messages

No static analysis issues come out of TypeScript -- it's considered a valid schema for that type.

What results did you expect?

I expected a TypeScript error saying something along the lines of "foo?" is incompatible with type "foo"

Are you going to resolve the issue?

I don't think I know how to, but happy to make an effort if this is indeed a valid bug.

slifty avatar Jul 11 '22 18:07 slifty

yes, typescript type utilities are not perfect - they push the limits of typescript to the point of type analyser (and my brain) cracking at seams - no way we can complicate it further, I am afraid...

cc @erikbrinkman, just in case I am wrong.

epoberezkin avatar Aug 31 '22 20:08 epoberezkin

There are two different issues here. The first was ensuring that nullable is false or absent. That was actually a bug that I just submitted a PR for.

The second is that required should have all non-null keys. The unfortunately is not possible in typescript. In the world we're talking about, the true type for required is all permutations of tuples of all the keys, e.g. the type ["a", "b"] or the type ["b", "a"]. There are some other discussions about this, but for various reasons this just isn't possible. If you really want this level of type checking you should look at JTD because its structure is more compatible with typescript's type system.

Thus after the PR your example will fail, but:

interface MyExample {
  foo: number;
}
const myExampleSchema: JSONSchemaType<MyExample> = {
  type: 'object',
  properties: {
    foo: {
      type: 'number',
    },
  },
  required: [],
}

will still pass, and there's not much JSONSchemaType can do about it. At least with my current awareness of the typescript type system. It may have been expanded recently, but I doubt it.

erikbrinkman avatar Sep 02 '22 20:09 erikbrinkman

Thank you both for engaging with this and for that bug fix -- honestly that alone will go a long way.

(I also want to mention how thankful I am for the TypeScript support that you've built into this library, it's really excellent and I appreciate how complicated it must have been to implement!)

slifty avatar Sep 03 '22 02:09 slifty