Skip to content

Commit 855fc9a

Browse files
Noyabronokclaude
andcommitted
fix(core): restore Required<Pick> for allOf required fields lost after normalizeAllOfSchema
When an allOf schema had an inline member that listed a property in `required` but the property was only defined on a sibling $ref member, the generated TypeScript type emitted the property as optional instead of required. `normalizeAllOfSchema` (introduced to fix #2458) merges inline allOf members into the parent schema, moving their `required` array onto `normalizedSchema`. The `requiredProperties` initializer in `combineSchemas` then read `schema.required` (always undefined on the original schema in this pattern) instead of `normalizedSchema.required`, so the promoted required fields were silently dropped and no `Required<Pick<...>>` was emitted. Fix: read `normalizedSchema.required` instead of `schema.required` when initializing `requiredProperties`. Closes #1670. Regression introduced by the normalizeAllOfSchema change that fixed #2458. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent bb79bf7 commit 855fc9a

3 files changed

Lines changed: 37 additions & 4 deletions

File tree

packages/core/src/getters/combine.test.ts

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ const context = {
3535
Base: {
3636
type: 'object',
3737
properties: {
38-
name: { type: 'string' },
38+
baseProp: { type: 'string' },
3939
},
4040
},
4141
Status: {
@@ -74,7 +74,7 @@ describe('combineSchemas (allOf required handling)', () => {
7474
it('keeps Required<Pick> when parent requires properties defined only in subschemas', () => {
7575
const schema: OpenApiSchemaObject = {
7676
type: 'object',
77-
required: ['name'],
77+
required: ['baseProp'],
7878
allOf: [{ $ref: '#/components/schemas/Base' }],
7979
};
8080

@@ -268,6 +268,32 @@ describe('combineSchemas (allOf required handling)', () => {
268268
});
269269
});
270270

271+
it('promotes required field to Required<Pick> when field is defined on $ref parent but required in inline allOf sibling', () => {
272+
const schema: OpenApiSchemaObject = {
273+
allOf: [
274+
{ $ref: '#/components/schemas/Base' },
275+
{
276+
type: 'object',
277+
required: ['baseProp'],
278+
properties: {
279+
url: { type: 'string' },
280+
},
281+
},
282+
],
283+
};
284+
285+
const result = combineSchemas({
286+
schema,
287+
name: 'Child',
288+
separator: 'allOf',
289+
context,
290+
nullable: '',
291+
});
292+
293+
expect(result.value).toContain('Required<Pick');
294+
expect(result.value).toContain("'baseProp'");
295+
});
296+
271297
it('normalizes inline object in allOf to match parent object form', () => {
272298
const variantA: OpenApiSchemaObject = {
273299
allOf: [

packages/core/src/getters/combine.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -283,7 +283,7 @@ export function combineSchemas({
283283
),
284284
requiredProperties:
285285
separator === 'allOf'
286-
? ((schema.required as string[] | undefined) ?? [])
286+
? ((normalizedSchema.required as string[] | undefined) ?? [])
287287
: [],
288288
};
289289
for (const subSchema of items) {

tests/__snapshots__/mock/issue-2465/model/retrievedUser.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,11 @@ import type { BaseUser } from './baseUser';
1111
*/
1212
export type RetrievedUser = BaseUser & {
1313
id: string;
14-
};
14+
} & Required<
15+
Pick<
16+
BaseUser & {
17+
id: string;
18+
},
19+
'lastName' | 'email'
20+
>
21+
>;

0 commit comments

Comments
 (0)