"AdditionalProperties" reflects onto existing properties and causes TypeScript compile errors
grepfruit19 opened this issue · comments
Description
When provided a schema that has additional properties, the generated TypeScript generates a "catch-all" key-value pair that causes compile errors.
Name | Version |
---|---|
openapi-typescript |
6.7.5 |
Node.js | 20.11.0 |
OS + version | macOS 14 |
Reproduction
Here is the JSON I'm converting
{
"openapi": "3.0.1",
"info": { "title": "TESTFILE", "version": "1.0.0" },
"security": [{ "Authorization": [] }],
"components": {
"schemas": {
"ErrorResponse": {
"type": "object",
"properties": {
"detailMessageArguments": {
"type": "array",
"items": { "type": "object" }
},
"detailMessageCode": { "type": "string" },
"titleMessageCode": { "type": "string" },
"headers": {
"type": "object",
"properties": {
"accessControlAllowHeaders": {
"type": "array",
"items": { "type": "string" }
},
"accessControlAllowOrigin": { "type": "string" },
"accessControlExposeHeaders": {
"type": "array",
"items": { "type": "string" }
},
"accessControlAllowCredentials": { "type": "boolean" },
"accessControlMaxAge": { "type": "integer", "format": "int64" },
"accessControlRequestHeaders": {
"type": "array",
"items": { "type": "string" }
},
"basicAuth": { "type": "string", "writeOnly": true },
"ifUnmodifiedSince": { "type": "integer", "format": "int64" },
"acceptCharset": {
"type": "array",
"items": { "type": "string" }
},
"all": {
"type": "object",
"additionalProperties": { "type": "string" },
"writeOnly": true
},
"lastModified": { "type": "integer", "format": "int64" },
"date": { "type": "integer", "format": "int64" },
"contentLength": { "type": "integer", "format": "int64" },
"ifModifiedSince": { "type": "integer", "format": "int64" }
},
"additionalProperties": {
"type": "array",
"items": { "type": "string" }
}
}
}
}
}
}
}
And here is the outputted TypeScript code:
export interface components {
schemas: {
ErrorResponse: {
detailMessageArguments?: Record<string, never>[];
detailMessageCode?: string;
titleMessageCode?: string;
headers?: {
accessControlAllowHeaders?: string[];
accessControlAllowOrigin?: string;
accessControlExposeHeaders?: string[];
accessControlAllowCredentials?: boolean;
/** Format: int64 */
accessControlMaxAge?: number;
accessControlRequestHeaders?: string[];
basicAuth?: string;
/** Format: int64 */
ifUnmodifiedSince?: number;
acceptCharset?: string[];
all?: {
[key: string]: string;
};
/** Format: int64 */
lastModified?: number;
/** Format: int64 */
date?: number;
/** Format: int64 */
contentLength?: number;
/** Format: int64 */
ifModifiedSince?: number;
[key: string]: string[] | undefined; // <------------ This is the line that's causing issues
};
};
};
responses: never;
parameters: never;
requestBodies: never;
headers: never;
pathItems: never;
}
If you attempt to parse this in TypeScript, it will give you errors such as
Property 'ifModifiedSince' of type 'number | undefined' is not assignable to 'string' index type 'string[] | undefined'.ts(2411)
This is occurring because additionalProperties is telling the object that all of its values should be string[], as opposed to just unlisted values.
Expected result
I don't know what the expected result should be honestly, but this doesn't compile so certainly not this. I'm not sure if this is a limitation of TypeScript as a language, if it is, maybe just generate something like [key: string]: unknown
?
Checklist
- My OpenAPI schema passes the Redocly validator (
npx @redocly/cli@latest lint
) - I’m willing to open a PR (see CONTRIBUTING.md)
This is a known issue and 7.x will NOT have | undefined
for this very reason. It originally meant to improve type safety and discourage use of additionalProperties
, but has caused issues in 6.x. Changing this would be a breaking change for many people, so it’s saved for the next major release.
This is already largely captured in #1055 (and other discussions); feel free to add to additional issues with more info if you’d like.