From cc959952ce39f31aca9c1435798269cb511f35bd Mon Sep 17 00:00:00 2001 From: WickyNilliams Date: Tue, 30 Jan 2024 11:48:58 +0000 Subject: [PATCH 1/4] add failing test --- packages/openapi-typescript/test/schema-object.test.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/openapi-typescript/test/schema-object.test.ts b/packages/openapi-typescript/test/schema-object.test.ts index a23be9f95..f58232d76 100644 --- a/packages/openapi-typescript/test/schema-object.test.ts +++ b/packages/openapi-typescript/test/schema-object.test.ts @@ -379,6 +379,11 @@ describe("Schema Object", () => { const generated = transformSchemaObject({ nullable: true }, options); expect(generated).toBe(`unknown`); }); + + test("nullable object", () => { + const generated = transformSchemaObject({ nullable: true, type: "object" }, options); + expect(generated).toBe(`Record | null`); + }); }); describe("schema composition", () => { From db5ee1f442ffc2190a79b367d84eb92ee59625e0 Mon Sep 17 00:00:00 2001 From: WickyNilliams Date: Tue, 30 Jan 2024 11:49:58 +0000 Subject: [PATCH 2/4] keep type information for nullable fields when possible --- .../openapi-typescript/src/transform/schema-object.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/openapi-typescript/src/transform/schema-object.ts b/packages/openapi-typescript/src/transform/schema-object.ts index a9b0f9206..4390af629 100644 --- a/packages/openapi-typescript/src/transform/schema-object.ts +++ b/packages/openapi-typescript/src/transform/schema-object.ts @@ -267,7 +267,13 @@ export function defaultSchemaObjectTransform(schemaObject: SchemaObject | Refere } // nullable (3.0) - if (schemaObject.nullable) finalType = tsUnionOf(finalType || "unknown", "null"); + if (schemaObject.nullable) { + if ("type" in schemaObject) { + finalType = tsUnionOf(finalType || "Record", "null"); + } else { + finalType = tsUnionOf(finalType || "unknown", "null"); + } + } if (finalType) return finalType; From 9329eba09e4a37bc83a883fcd8f15c1b58bbb5b0 Mon Sep 17 00:00:00 2001 From: WickyNilliams Date: Tue, 30 Jan 2024 12:29:05 +0000 Subject: [PATCH 3/4] update snapshots --- .../examples/digital-ocean-api.ts | 4 +- .../openapi-typescript/examples/github-api.ts | 122 +++++++++--------- 2 files changed, 63 insertions(+), 63 deletions(-) diff --git a/packages/openapi-typescript/examples/digital-ocean-api.ts b/packages/openapi-typescript/examples/digital-ocean-api.ts index cdb86509b..c67299321 100644 --- a/packages/openapi-typescript/examples/digital-ocean-api.ts +++ b/packages/openapi-typescript/examples/digital-ocean-api.ts @@ -9085,7 +9085,7 @@ export interface external { * @description The Droplet that the floating IP has been assigned to. When you query a floating IP, if it is assigned to a Droplet, the entire Droplet object will be returned. If it is not assigned, the value will be null. * @example null */ - droplet?: unknown; + droplet?: (Record | null) | external["resources/droplets/models/droplet.yml"]; /** * @description A boolean value indicating whether or not the floating IP has pending actions preventing new ones from being submitted. * @example true @@ -13948,7 +13948,7 @@ export interface external { * @description The Droplet that the reserved IP has been assigned to. When you query a reserved IP, if it is assigned to a Droplet, the entire Droplet object will be returned. If it is not assigned, the value will be null. * @example null */ - droplet?: unknown; + droplet?: (Record | null) | external["resources/droplets/models/droplet.yml"]; /** * @description A boolean value indicating whether or not the reserved IP has pending actions preventing new ones from being submitted. * @example true diff --git a/packages/openapi-typescript/examples/github-api.ts b/packages/openapi-typescript/examples/github-api.ts index b3cb2967d..be2c0566e 100644 --- a/packages/openapi-typescript/examples/github-api.ts +++ b/packages/openapi-typescript/examples/github-api.ts @@ -26074,7 +26074,7 @@ export interface components { created_at: string; /** @description The time that the alert was dismissed in ISO 8601 format: `YYYY-MM-DDTHH:MM:SSZ`. */ dismissed_at: string | null; - dismissed_by: unknown; + dismissed_by: Record | null; /** @description The reason for dismissing or closing the alert. Can be one of: `false positive`, `won't fix`, and `used in tests`. */ dismissed_reason: string | null; /** @@ -27160,7 +27160,7 @@ export interface components { display_title: string; event: string; head_branch: string; - head_commit?: unknown; + head_commit?: Record | null; head_repository?: { archive_url?: string; assignees_url?: string; @@ -27531,7 +27531,7 @@ export interface components { created_at: string; event: string; head_branch: string; - head_commit?: unknown; + head_commit?: Record | null; head_repository?: { archive_url?: string; assignees_url?: string; @@ -27910,7 +27910,7 @@ export interface components { created_at: string; event: string; head_branch: string; - head_commit?: unknown; + head_commit?: Record | null; head_repository?: { archive_url?: string; assignees_url?: string; @@ -29960,7 +29960,7 @@ export interface components { labels_url?: string; language?: unknown; languages_url?: string; - license?: unknown; + license?: Record | null; merges_url?: string; milestones_url?: string; mirror_url?: unknown; @@ -30941,7 +30941,7 @@ export interface components { /** Format: uri */ url?: string; }) | null; - assignees?: unknown[]; + assignees?: (Record | null)[]; author_association?: string; body?: string | null; closed_at?: string | null; @@ -30968,10 +30968,10 @@ export interface components { })[]; labels_url?: string; locked: boolean; - milestone?: unknown; + milestone?: Record | null; node_id?: string; number?: number; - performed_via_github_app?: unknown; + performed_via_github_app?: Record | null; reactions?: { "+1"?: number; "-1"?: number; @@ -31555,7 +31555,7 @@ export interface components { /** Format: uri */ url?: string; }) | null; - assignees?: unknown[]; + assignees?: (Record | null)[]; author_association?: string; body?: string | null; closed_at?: string | null; @@ -31582,10 +31582,10 @@ export interface components { })[]; labels_url?: string; locked: boolean; - milestone?: unknown; + milestone?: Record | null; node_id?: string; number?: number; - performed_via_github_app?: unknown; + performed_via_github_app?: Record | null; reactions?: { "+1"?: number; "-1"?: number; @@ -32176,7 +32176,7 @@ export interface components { /** Format: uri */ url?: string; }) | null; - assignees?: unknown[]; + assignees?: (Record | null)[]; author_association?: string; body?: string | null; closed_at?: string | null; @@ -32203,10 +32203,10 @@ export interface components { })[]; labels_url?: string; locked: boolean; - milestone?: unknown; + milestone?: Record | null; node_id?: string; number?: number; - performed_via_github_app?: unknown; + performed_via_github_app?: Record | null; reactions?: { "+1"?: number; "-1"?: number; @@ -33131,8 +33131,8 @@ export interface components { }) | null; }) & ({ active_lock_reason?: string | null; - assignee?: unknown; - assignees?: unknown[]; + assignee?: Record | null; + assignees?: (Record | null)[]; author_association?: string; body?: string | null; closed_at: string | null; @@ -33142,13 +33142,13 @@ export interface components { events_url?: string; html_url?: string; id?: number; - labels?: unknown[]; + labels?: (Record | null)[]; labels_url?: string; locked?: boolean; - milestone?: unknown; + milestone?: Record | null; node_id?: string; number?: number; - performed_via_github_app?: unknown; + performed_via_github_app?: Record | null; reactions?: { "+1"?: number; "-1"?: number; @@ -34026,8 +34026,8 @@ export interface components { }) | null; }) & ({ active_lock_reason?: string | null; - assignee?: unknown; - assignees?: unknown[]; + assignee?: Record | null; + assignees?: (Record | null)[]; author_association?: string; body?: string | null; closed_at?: string | null; @@ -34037,7 +34037,7 @@ export interface components { events_url?: string; html_url?: string; id?: number; - labels?: unknown[]; + labels?: (Record | null)[]; labels_url?: string; locked?: boolean; /** @@ -34113,7 +34113,7 @@ export interface components { }) | null; node_id?: string; number?: number; - performed_via_github_app?: unknown; + performed_via_github_app?: Record | null; reactions?: { "+1"?: number; "-1"?: number; @@ -35525,8 +35525,8 @@ export interface components { }) & ({ /** @enum {string|null} */ active_lock_reason: "resolved" | "off-topic" | "too heated" | "spam" | null; - assignee?: unknown; - assignees?: unknown[]; + assignee?: Record | null; + assignees?: (Record | null)[]; author_association?: string; body?: string | null; closed_at?: string | null; @@ -35536,14 +35536,14 @@ export interface components { events_url?: string; html_url?: string; id?: number; - labels?: unknown[]; + labels?: (Record | null)[]; labels_url?: string; /** @enum {boolean} */ locked: true; - milestone?: unknown; + milestone?: Record | null; node_id?: string; number?: number; - performed_via_github_app?: unknown; + performed_via_github_app?: Record | null; reactions?: { "+1"?: number; "-1"?: number; @@ -36000,8 +36000,8 @@ export interface components { }) | null; }) & ({ active_lock_reason?: string | null; - assignee?: unknown; - assignees?: unknown[]; + assignee?: Record | null; + assignees?: (Record | null)[]; author_association?: string; body?: string | null; closed_at?: string | null; @@ -36011,7 +36011,7 @@ export interface components { events_url?: string; html_url?: string; id?: number; - labels?: unknown[]; + labels?: (Record | null)[]; labels_url?: string; locked?: boolean; /** @@ -36087,7 +36087,7 @@ export interface components { }; node_id?: string; number?: number; - performed_via_github_app?: unknown; + performed_via_github_app?: Record | null; reactions?: { "+1"?: number; "-1"?: number; @@ -38102,8 +38102,8 @@ export interface components { }) | null; }) & ({ active_lock_reason?: string | null; - assignee?: unknown; - assignees?: unknown[]; + assignee?: Record | null; + assignees?: (Record | null)[]; author_association?: string; body?: string | null; closed_at?: string | null; @@ -38113,13 +38113,13 @@ export interface components { events_url?: string; html_url?: string; id?: number; - labels?: unknown[]; + labels?: (Record | null)[]; labels_url?: string; locked?: boolean; - milestone?: unknown; + milestone?: Record | null; node_id?: string; number?: number; - performed_via_github_app?: unknown; + performed_via_github_app?: Record | null; reactions?: { "+1"?: number; "-1"?: number; @@ -40547,8 +40547,8 @@ export interface components { }) | null; }) & ({ active_lock_reason: unknown; - assignee?: unknown; - assignees?: unknown[]; + assignee?: Record | null; + assignees?: (Record | null)[]; author_association?: string; body?: string | null; closed_at?: string | null; @@ -40558,11 +40558,11 @@ export interface components { events_url?: string; html_url?: string; id?: number; - labels?: unknown[]; + labels?: (Record | null)[]; labels_url?: string; /** @enum {boolean} */ locked: false; - milestone?: unknown; + milestone?: Record | null; node_id?: string; number?: number; performed_via_github_app?: unknown; @@ -43025,14 +43025,14 @@ export interface components { }) | null; body?: string | Record; body_html?: string; - container_metadata?: { - labels?: unknown; - manifest?: unknown; + container_metadata?: ({ + labels?: Record | null; + manifest?: Record | null; tag?: { digest?: string; name?: string; }; - } | null; + }) | null; created_at?: string; description: string; docker_metadata?: { @@ -43048,23 +43048,23 @@ export interface components { [key: string]: unknown; }[]; name: string; - npm_metadata?: { + npm_metadata?: ({ name?: string; version?: string; npm_user?: string; - author?: unknown; - bugs?: unknown; + author?: Record | null; + bugs?: Record | null; dependencies?: Record; dev_dependencies?: Record; peer_dependencies?: Record; optional_dependencies?: Record; description?: string; - dist?: unknown; + dist?: Record | null; git_head?: string; homepage?: string; license?: string; main?: string; - repository?: unknown; + repository?: Record | null; scripts?: Record; id?: string; node_version?: string; @@ -43077,7 +43077,7 @@ export interface components { files?: string[]; bin?: Record; man?: Record; - directories?: unknown; + directories?: Record | null; os?: string[]; cpu?: string[]; readme?: string; @@ -43086,7 +43086,7 @@ export interface components { commit_oid?: string; published_via_actions?: boolean; deleted_by_id?: number; - } | null; + }) | null; nuget_metadata?: (({ id?: number | string; name?: string; @@ -75635,8 +75635,8 @@ export interface components { body?: string | Record; body_html?: string; container_metadata?: { - labels?: unknown; - manifest?: unknown; + labels?: Record | null; + manifest?: Record | null; tag?: { digest?: string; name?: string; @@ -75899,7 +75899,7 @@ export interface components { updated_at: string; version: string; }; - registry: unknown; + registry: Record | null; updated_at: string; }; repository?: components["schemas"]["repository-webhooks"]; @@ -76540,7 +76540,7 @@ export interface components { /** Format: uri */ zipball_url: string | null; }) & ({ - assets?: unknown[]; + assets?: (Record | null)[]; assets_url?: string; author?: { avatar_url?: string; @@ -76735,7 +76735,7 @@ export interface components { /** Format: uri */ zipball_url: string | null; }) & ({ - assets?: unknown[]; + assets?: (Record | null)[]; assets_url?: string; author?: { avatar_url?: string; @@ -77084,7 +77084,7 @@ export interface components { /** Format: uri */ zipball_url: string | null; }) & ({ - assets?: unknown[]; + assets?: (Record | null)[]; assets_url?: string; author?: { avatar_url?: string; @@ -80761,7 +80761,7 @@ export interface components { head_branch?: string | null; /** @description The name of the workflow. */ workflow_name?: string | null; - steps?: unknown[]; + steps?: (Record | null)[]; url?: string; }); deployment?: components["schemas"]["deployment"]; @@ -81555,7 +81555,7 @@ export interface components { node_id?: string; path?: string; previous_attempt_url?: string | null; - pull_requests?: unknown[]; + pull_requests?: (Record | null)[]; referenced_workflows?: { path: string; ref?: string; @@ -82242,7 +82242,7 @@ export interface components { node_id?: string; path?: string; previous_attempt_url?: string | null; - pull_requests?: unknown[]; + pull_requests?: (Record | null)[]; referenced_workflows?: { path: string; ref?: string; From fe6c6d1526c59e4f9021d71cad74feba315f337f Mon Sep 17 00:00:00 2001 From: WickyNilliams Date: Tue, 30 Jan 2024 12:36:08 +0000 Subject: [PATCH 4/4] add changeset --- .changeset/loud-items-hope.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/loud-items-hope.md diff --git a/.changeset/loud-items-hope.md b/.changeset/loud-items-hope.md new file mode 100644 index 000000000..1c9f151f0 --- /dev/null +++ b/.changeset/loud-items-hope.md @@ -0,0 +1,5 @@ +--- +"openapi-typescript": patch +--- + +Keep type information for nullable fields when possible