Option for adding `undefined` to optional union for optional properties.
Opened this issue · 3 comments
In TypeScript, when exactOptionalPropertyTypes
is set to true, properties that are optional?:
but not do not include | undefined
in their union can not be assigned a value of undefined.
For generating code that will be consumed by others, we may not want to force them to turn off exactOptionalPropertyTypes
. For that please consider an option to include undefined
in generated type unions of non-required properties.
Could you share an example of a JSON schema and the output it produces today, and how exactly that might cause issues for users?
No problem. Given the schema,
{
"title": "Example Schema",
"type": "object",
"properties": {
"firstName": {
"type": "string"
},
"age": {
"type": "integer",
"minimum": 0
}
},
"additionalProperties": false,
"required": ["firstName"]
}
the library currently produces the following output:
export interface ExampleSchema {
firstName: string;
age?: number;
}
Let's say we have a function,
function testFunction(data: ExampleSchema) { /* ... */ }
Calling that function with age
set to undefined
raises a TypeScript error when the TS compiler option exactOptionalPropertyTypes
is true:
testFunction({
firstName: "John",
age: undefined
});
/*
Argument of type '{ firstName: string; age: undefined; }' is not assignable to parameter of type 'ExampleSchema' with 'exactOptionalPropertyTypes: true'. Consider adding 'undefined' to the types of the target's properties.
Types of property 'age' are incompatible.
Type 'undefined' is not assignable to type 'number'.
*/
The solution in the above is to simply omit the property altogether, but if the value of age is coming from another possibly undefined variable, things get messier:
const age: number | undefined = undefined;
testFunction({
firstName: "John",
...(age ? { age: age } : {})
});
Our code may internally equate the non-existence of an optional type with the existence a value of undefined
. This seems to be common behavior in many libraries. If there does need to be a distinction, like with updating a record, using null
seems to be the most widely implemented practice.
Thusly I propose a new option in json-schema-to-typescript
to address this use case. Possible names include undefinedOptionals
and undefinedOptionalProperties
.
The following would be the output of the above schema with this flag enabled:
export interface ExampleSchema {
firstName: string;
age?: number | undefined;
}
testFunction({
firstName: "John",
age: undefined // Ok
});
Gotcha. That sounds reasonable to me. I think the more explicit undefinedOptionalProperties
is a bit nicer. PRs welcome.