ajv: `undefined` treated as `null`able in JSONSchemaType
What version of Ajv are you using? Does the issue happen if you use the latest version?
7.0.2, yes
Your typescript code
const testSchema: JSONSchemaType<{ a?: string }> = {
type: "object",
properties: { a: { type: "string" } },
required: [],
};
produces the following error, but
const testSchema: JSONSchemaType<{ a: string | null }> = {
type: "object",
properties: { a: { type: "string" } },
required: ["a"],
};
type checks fine.
Typescript compiler error messages
error TS2322: Type '{ type: "string"; }' is not assignable to type '{ $ref: string; } | ({ type: "string"; minLength?: number | undefined; maxLength?: number | undefined; pattern?: string | undefined; format?: string | undefined; } & { [keyword: string]: any; ... 10 more ...; not?: Partial<...> | undefined; } & { ...; })'.
Type '{ type: "string"; }' is not assignable to type '{ type: "string"; minLength?: number | undefined; maxLength?: number | undefined; pattern?: string | undefined; format?: string | undefined; } & { [keyword: string]: any; $id?: string | undefined; ... 9 more ...; not?: Partial<...> | undefined; } & { ...; }'.
Property 'nullable' is missing in type '{ type: "string"; }' but required in type '{ nullable: true; const?: undefined; enum?: (string | null | undefined)[] | undefined; default?: string | null | undefined; }'.
properties: { a: { type: "string" } },
~
node_modules/ajv/dist/types/json-schema.d.ts:95:5
95 nullable: true;
~~~~~~~~
'nullable' is declared here.
Describe the change that should be made to address the issue?
In essence the current type definition says that any non-required field should be nullable, but there is a distinction between null and undefined. I think the change should just be making this line null extends T
instead of undefined extends T
I could also see another change that adds undefined to possible values in enum / default if undefined extends T
, but maybe that’s not necessary since in general json does not allow for undefined values.
This change would also be breaking since the second example will now error as it used to compile (although the error seems correct).
Are you going to resolve the issue?
I can, but I’m seeking guidance on the fix first. Javascript distinguishes between undefined
and null
but json doesn’t, or more specifically undefined
would imply an omitted field, where as null
is a value. However, it’s not that simple since in some cases it seems that undefined values are omitted (in the case of object values) whereas in other cases they’re serialized as a null value (array elements). Therefore this change doesn’t seem super straightforward.
About this issue
- Original URL
- State: closed
- Created 3 years ago
- Reactions: 15
- Comments: 17 (5 by maintainers)
I feel like this is the breaking change that may thwart my type implementations. At an API level, sending an PUT request of
{id: 123, a: 'hello'}
is VERY different to{id: 123, a: 'hello', b: NULL}
. The second is clearing the field. Unfortunately there is no was to consistently represent the first because AJV forces you to accept a NULL in the field.EDIT: I see v9 has it, thanks. When is the release on NPM?
For anyone else like me who was confused:
If you want to define your Type like:
And you want Ajv to correctly check it and allow a string or null like such:
But don’t want
JSONSchemaType
complaining and forcing you to define your Type like this:Then you need the use the inverse of @erikbrinkman proposed (though it was very helpful in pointing me in the right direction). You’ll want something like this:
And you’ll use it like this:
With all that in place the following will be true:
And your data (that you pass into
validate
) will be correctly typed as:I hope this helps someone else. Personally I despise using
undefined
in place ofnull
(they are very different) especially when passing data between client<->server so I was very glad to find a way to wrangle this library to handle all my validation while also using types the way that works best for me.I’m running into issues with Ajv requiring
"nullable": true
for every non-required property as well. Considering copy-pasting https://github.com/ajv-validator/ajv/blob/v9/lib/types/json-schema.ts to my project for now as that seems to get around it. Thanks for the clue @JamesJansson.now i make a copy of
JSONSchemaType
from Ajv , the new code in follow:i fix two place, the
RequiredMembers
and theNullable
, now all are ok.if any other have face same issue like me, you can try to make a copy file of
JSONSchemaType.ts
, fix that like above , import this one instead of the Ajv versioin.I agree, it is quite an opinionated choice of how an optional field should be represented in JSON.
The reason for this choice is that it is quite common to allow null for optional fields in JSON and most typescript apps would not normally distinguish how null and undefined are processed…
This choice is partially made because you could use something like
string | null
in typescript but JSONSchemaType<T> doesn’t yet support unions so it would simply not work with it…It is a relatively experimental new thing, but it’s usage is completely optional, as the doc says.
I am considering what’s the best way to evolve it - supporting unions would be a very valuable addition. Then we can possibly parameterise this choice via the second parameter of this type (and possibly change the current default to require nullable in v8)
Thank you - will close it then - let’s see what people ask for after all the changes to JSONSchemaType are released
@epoberezkin I think the change I suggested, adding an extra parameter to the type makes sense and should be viable.
However, I’m using jtd now which has more explicit treatment of the difference between undefined an null, so I don’t really care as much.
I’m happy to still put up a patch of you think it’s useful, but given that I’m the only one who’s complained, and I don’t care anymore, it seems like the added work and complexity aren’t justified.
i got the same error in all case.
what ever the
vLib
in or not in therequired
list , the follow error also omit on webstorm.and only can add
nullable: true
to avoid this error notice.or use
// @ts-ignore
line by line.so, now i cannot have a non-nullable field, if i dont want the error notice or the ts-ignore.
but in other siide, the code compile well, i think this is only a type check system error.
i seems that the code is follow :
i’m using ajv 7.0.3 , and webstorm 2020.3.1/2020.3 .