Summary#
OpenAPI TypeScript client codegen에서 oneOf + discriminator 조합에 allOf 상속/합성과 nullable 처리가 함께 들어가면, 생성기가 동일 속성을 중복 선언하거나 discriminator 필드를 여러 계층에서 반복 생성하는 failure mode가 발생할 수 있다. 핵심 원인은 OpenAPI 스키마의 의미론적 합성 모델과 TypeScript의 구조적 타입/클래스 생성 전략 사이의 불일치이며, 특히 codegen 내부의 schema normalization 단계가 allOf flattening, nullable union화, discriminator mapping 해석을 일관되게 처리하지 못할 때 재현된다.
실무적으로는 다음과 같은 패턴이 위험하다.
components:
schemas:
Pet:
type: object
required: [kind]
properties:
kind:
type: string
discriminator:
propertyName: kind
mapping:
cat: '#/components/schemas/Cat'
Cat:
allOf:
- $ref: '#/components/schemas/Pet'
- type: object
required: [kind, name]
properties:
kind:
type: string
enum: [cat]
name:
type: string
nullable: true
이 구조에서 생성기는 Pet.kind와 Cat.kind를 모두 보존하거나, nullable: true를 별도 wrapper/union으로 정규화하면서 name 또는 discriminator 관련 속성을 중복 모델 필드로 출력할 수 있다. 결과적으로 TypeScript 컴파일 오류, 잘못된 runtime serializer/deserializer, 또는 discriminator narrowing 실패가 발생한다.
Key Points#
oneOf+discriminator는 OpenAPI에서 다형성 모델링을 위한 표준 패턴이다.allOf는 상속처럼 쓰이지만, OpenAPI 의미론상 “객체 합성”에 가깝다. codegen이 이를 클래스 상속으로 강제 변환하면 속성 중복 문제가 생길 수 있다.nullable은 OpenAPI 3.0에서 별도 키워드이며, JSON Schema의type: ["string", "null"]와 동일하게 표현되지 않는다. 생성기마다 이를T | null, optional field, wrapper schema 등으로 다르게 정규화한다.- failure mode는 대체로 다음 조건에서 나타난다.
- base schema에 discriminator property가 정의됨.
- child schema가
allOf로 base를 참조함. - child schema가 discriminator property를 다시
enum또는const유사 패턴으로 재정의함. - child schema 또는 합성된 하위 property에
nullable: true가 포함됨. - generator가
allOfflattening과 discriminator mapping을 동시에 수행함. - 흔한 증상:
- TypeScript interface/class에 동일 property가 두 번 생성됨.
- 부모/자식 모델 양쪽에 discriminator field가 중복됨.
oneOfunion type이 discriminator 기준으로 좁혀지지 않음.nullableproperty가T | null | undefined처럼 과도하게 확장됨.- generated model import가 순환 참조 또는 duplicate identifier 오류를 냄.
- 실무 workaround:
- discriminator field는 가능하면 base schema에만 선언한다.
- child schema에서는 discriminator 값을 문서화하되 property를 재정의하지 않는다.
- generator가 지원한다면
legacyDiscriminatorBehavior,useUnionTypes,disallowAdditionalPropertiesIfNotPresent,withoutRuntimeChecks등 관련 옵션을 비교 테스트한다. allOf상속 모델 대신 명시적 flat schema를 사용해 codegen 입력을 단순화한다.- OpenAPI 3.1 사용 시
nullable대신 JSON Schema 방식의type: ["string", "null"]또는oneOf: [{type: string}, {type: "null"}]표현으로 일관화한다. - codegen 전 pre-normalization script를 두어 discriminator property 중복, nullable wrapper,
allOfflattening을 통제한다. - capsule 재사용 포인트:
- 이 문제는 특정 generator 하나의 단순 버그라기보다 OpenAPI composition semantics와 TypeScript emission strategy 사이의 반복적인 경계 문제다.
- generator별 issue를 볼 때도 “duplicate fields” 자체보다 “schema normalization order”를 함께 추적해야 한다.
- 재현 fixture는
base discriminator schema+child allOf schema+child discriminator enum override+nullable field네 요소를 최소 단위로 구성하면 좋다.
Cautions#
- 현재 환경에서는 사용자가 요구한 실제
WebSearch도구가 제공되지 않아, 실시간 검색 결과를 직접 확인하지 못했다. - 아래 Sources는 공개적으로 알려진 OpenAPI/OpenAPI Generator 관련 문서 URL 중심이다. 특정 GitHub issue 번호나 generator별 최신 regression 여부는 별도 웹 검증이 필요하다.
openapi-generator,swagger-codegen,openapi-typescript-codegen,openapi-typescript는 discriminator와 composition 처리 방식이 서로 다르다. 하나의 workaround가 모든 생성기에 동일하게 적용되지는 않는다.- OpenAPI 3.0의
nullable과 OpenAPI 3.1의 JSON Schema null 표현은 다르므로, generator가 어느 OpenAPI 버전을 기준으로 해석하는지 반드시 확인해야 한다. - child schema에서 discriminator property를 재정의하는 패턴은 문서상 의도 표현에는 유용하지만, codegen에는 중복 필드 또는 충돌을 유발할 수 있다.
allOf를 “상속”으로 설명하는 문서와 도구가 많지만, OpenAPI/JSON Schema 관점에서는 제약 조건의 결합이다. 이 차이가 codegen failure의 근본 원인 중 하나다.
Sources#
- https://swagger.io/docs/specification/v3_0/data-models/inheritance-and-polymorphism/
- https://swagger.io/docs/specification/v3_0/data-models/data-types/#null
- https://spec.openapis.org/oas/v3.0.3.html
- https://spec.openapis.org/oas/v3.1.0.html
- https://openapi-generator.tech/docs/generators/typescript/
- https://openapi-generator.tech/docs/generators/typescript-fetch/
- https://github.com/OpenAPITools/openapi-generator
- https://github.com/ferdikoomen/openapi-typescript-codegen
Related#
- OpenAPI Codegen Failure Mode: oneOf Discriminator Duplication with allOf and Nullable Schemas
- OpenAPI TypeScript Codegen Failure Modes: oneOf Discriminator Duplication, allOf Flattening, and Nullable Normalization
- Discriminator Schema Drift Failure Modes and CI Guardrails
Sagwan Revalidation 2026-05-25T16:16:00Z#
- verdict:
ok - note: [chatgpt 오류] The read operation timed out
Sagwan Revalidation 2026-05-26T16:22:14Z#
- verdict:
ok - note: oneOf/discriminator/allOf/nullable codegen 위험은 여전히 실무적으로 유효함
Sagwan Revalidation 2026-05-27T16:26:17Z#
- verdict:
ok - note: OAS 3.0/3.1 codegen의 다형성 정규화 위험 설명은 여전히 유효함
Sagwan Revalidation 2026-05-28T17:25:47Z#
- verdict:
ok - note: OpenAPI 3.x codegen의 allOf/discriminator/nullable 위험은 여전히 유효함
Sagwan Revalidation 2026-05-29T17:59:25Z#
- verdict:
ok - note: 전날 검증 이후 관련 OpenAPI/codegen 관행 변화가 없어 내용은 여전히 유효함
Sagwan Revalidation 2026-05-30T18:36:20Z#
- verdict:
ok - note: 일반적 failure mode와 권장 관점이 현재도 유효함
Sagwan Revalidation 2026-05-31T18:40:12Z#
- verdict:
ok - note: 최근 관행과 OpenAPI 3.0/TS codegen failure mode 설명이 여전히 유효함
Sagwan Revalidation 2026-06-01T18:40:40Z#
- verdict:
ok - note: [chatgpt HTTP 401] {
Sagwan Revalidation 2026-06-02T22:06:21Z#
- verdict:
ok - note: OpenAPI 3.0 nullable·allOf·discriminator codegen 위험은 여전히 유효함
Sagwan Revalidation 2026-06-03T23:37:27Z#
- verdict:
ok - note: OpenAPI codegen의 다형성·nullable 실패 모드는 여전히 유효함
Sagwan Revalidation 2026-06-05T00:05:31Z#
- verdict:
ok - note: 최근 관행과 OpenAPI/codegen failure mode 설명이 여전히 유효함
Sagwan Revalidation 2026-06-06T00:42:17Z#
- verdict:
ok - note: 최근 변화 가능성 낮고 OpenAPI/codegen failure mode 설명은 여전히 유효함
Sagwan Revalidation 2026-06-07T00:43:42Z#
- verdict:
ok - note: oneOf/discriminator와 allOf/nullable 코드젠 실패 모드는 여전히 유효함
Sagwan Revalidation 2026-06-08T00:51:29Z#
- verdict:
ok - note: OAS 3.0 nullable·allOf·discriminator codegen 위험은 여전히 유효함
Sagwan Revalidation 2026-06-09T01:21:04Z#
- verdict:
ok - note: 일반적 failure mode와 OAS 3.0 nullable 설명은 현재도 유효함
Sagwan Revalidation 2026-06-10T08:27:19Z#
- verdict:
ok - note: OAS 3.0 nullable·allOf·discriminator codegen 위험 설명은 여전히 유효함
Sagwan Revalidation 2026-06-11T08:43:15Z#
- verdict:
ok - note: OpenAPI 합성·nullable·discriminator 관련 codegen 위험은 여전히 유효함
Sagwan Revalidation 2026-06-12T09:07:07Z#
- verdict:
ok - note: [chatgpt HTTP 401] {
Sagwan Revalidation 2026-06-13T09:51:18Z#
- verdict:
ok - note: OAS 3.x 합성/nullable과 TS codegen failure mode 설명은 여전히 유효함
Sagwan Revalidation 2026-06-14T10:12:00Z#
- verdict:
ok - note: OpenAPI 합성/nullable/codegen failure mode 설명은 현재도 유효함
Sagwan Revalidation 2026-06-15T10:52:31Z#
- verdict:
ok - note: oneOf/discriminator/allOf/nullable codegen 위험성은 여전히 유효함
Sagwan Revalidation 2026-06-16T11:02:26Z#
- verdict:
ok - note: oneOf/discriminator와 allOf/nullable codegen 위험은 여전히 유효함
Sagwan Revalidation 2026-06-17T11:52:09Z#
- verdict:
ok - note: oneOf/allOf/discriminator/nullable codegen 위험은 여전히 유효함
Sagwan Revalidation 2026-06-18T11:56:17Z#
- verdict:
ok - note: OAS 합성/nullable와 TS codegen failure mode 설명은 여전히 유효함
Sagwan Revalidation 2026-06-19T13:20:22Z#
- verdict:
ok - note: OpenAPI 합성/nullable/codegen 중복 위험은 여전히 유효한 실무 주의점임
Sagwan Revalidation 2026-06-20T13:57:53Z#
- verdict:
ok - note: OpenAPI 다형성 codegen의 합성·nullable 위험 설명은 현재도 유효함
Sagwan Revalidation 2026-06-21T14:53:51Z#
- verdict:
ok - note: OpenAPI oneOf/allOf/nullable codegen 위험 설명은 현재도 유효함
Sagwan Revalidation 2026-06-22T15:06:57Z#
- verdict:
ok - note: [chatgpt HTTP 401] {
Sagwan Revalidation 2026-06-23T15:27:49Z#
- verdict:
ok - note: [chatgpt HTTP 401] {
Sagwan Revalidation 2026-06-24T15:46:30Z#
- verdict:
ok - note: [chatgpt HTTP 401] {
Sagwan Revalidation 2026-06-25T16:40:59Z#
- verdict:
ok - note: OAS 합성·nullable·discriminator codegen 위험 설명은 여전히 유효함
Sagwan Revalidation 2026-06-26T20:58:09Z#
- verdict:
ok - note: OpenAPI 다형성 codegen의 구조적 한계 설명으로 여전히 유효함
Sagwan Revalidation 2026-06-27T23:18:59Z#
- verdict:
ok - note: OpenAPI 다형성/codegen 실패 패턴과 권장 주의점은 여전히 유효함
Sagwan Revalidation 2026-06-28T23:58:31Z#
- verdict:
ok - note: OpenAPI codegen의 oneOf/allOf/nullable 중복 위험 설명은 여전히 유효함
Sagwan Revalidation 2026-06-30T00:33:22Z#
- verdict:
ok - note: 최근 관행과 OpenAPI 의미론상 여전히 유효한 실패 모드 설명이다.
Sagwan Revalidation 2026-07-01T06:13:08Z#
- verdict:
ok - note: OpenAPI 합성·nullable·discriminator codegen 위험 설명은 여전히 유효함
Sagwan Revalidation 2026-07-02T17:06:10Z#
- verdict:
ok - note: oneOf/discriminator/allOf/nullable codegen 위험 설명은 여전히 유효함
Sagwan Revalidation 2026-07-04T05:19:37Z#
- verdict:
ok - note: OpenAPI 3.x codegen의 합성·discriminator 주의점은 여전히 유효함
Sagwan Revalidation 2026-07-05T08:21:43Z#
- verdict:
ok - note: 일반적 failure mode와 권장 주의점이 여전히 유효하다.
Sagwan Revalidation 2026-07-06T14:18:26Z#
- verdict:
ok - note: OAS 3.0 nullable·allOf·discriminator 관련 codegen 위험은 여전히 유효함
Sagwan Revalidation 2026-07-07T20:23:27Z#
- verdict:
ok - note: OAS 3.0 nullable/allOf/discriminator codegen 위험은 여전히 유효함
Sagwan Revalidation 2026-07-09T17:43:12Z#
- verdict:
ok - note: 최근 practice와 충돌 없고 failure mode 설명도 여전히 유효함
Sagwan Revalidation 2026-07-11T10:28:22Z#
- verdict:
ok - note: OpenAPI 3.0 nullable·allOf·discriminator codegen 주의점은 여전히 유효함
Sagwan Revalidation 2026-07-13T04:36:08Z#
- verdict:
ok - note: 일반적 failure mode와 OAS 3.0 nullable 설명이 여전히 유효함
Sagwan Revalidation 2026-07-15T03:33:55Z#
- verdict:
ok - note: 최근 관행과도 부합하며 핵심 failure mode 설명이 여전히 유효함
Sagwan Revalidation 2026-07-17T04:11:56Z#
- verdict:
ok - note: 일반적 failure mode와 권장 해석이 현재도 유효해 보임
Sagwan Revalidation 2026-07-19T05:59:28Z#
- verdict:
ok - note: oneOf/discriminator+allOf/nullable codegen 위험은 현재도 유효하다.
Sagwan Revalidation 2026-07-21T07:10:57Z#
- verdict:
ok - note: oneOf/discriminator/allOf/nullable codegen 위험은 여전히 유효함