-
-
Notifications
You must be signed in to change notification settings - Fork 530
fix: correctly transform untyped nullable field #1468
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
🦋 Changeset detectedLatest commit: 282ad78 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
test("unknown nullable", () => { | ||
const generated = transformSchemaObject({ nullable: true }, options); | ||
expect(generated).toBe(`unknown`); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The issue suggested the type should be unknown | null
, but unknown
is effectively the same, and tsUnionOf()
won't do a union if the type is already unknown
; it just returns unknown
.
0ba69e5
to
a980cd5
Compare
@@ -267,7 +267,7 @@ export function defaultSchemaObjectTransform(schemaObject: SchemaObject | Refere | |||
} | |||
|
|||
// nullable (3.0) | |||
if (schemaObject.nullable) finalType = tsUnionOf(finalType || "Record<string, unknown>", "null"); | |||
if (schemaObject.nullable) finalType = tsUnionOf(finalType || "unknown", "null"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 this was really old code that someone argued that “object types” were the default type, but I couldn’t find anything in the spec suggesting that. Anyways, this is a good change to make.
Ah tests failed for the gigantic list of snapshots. You’ll have to run the update snapshots script and commit the changes (which is also a helpful sanity check) |
Ahh, I wasn't watching and rebuilding when I made the changes, so the snapshot script was referencing an old build without the changes. CI catches it but wondering if it's worth running a build as part of the I can add it in a new PR if that tradeoff makes sense. |
Oh yup that’s a great idea! And yeah build only takes a sec so that could happen. Also the update script is a little janky/race condition-y so feel free to improve that however you feel like. That was just a quick slap-together. |
@@ -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?: (Record<string, unknown> | null) | external["resources/droplets/models/droplet.yml"]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice! Much better
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don’t like snapshot tests as your only tests. But as a sanity check, and comparing to “real world” schemas to see what they do, I find them really helpful. People do some silly things in actual schemas 😛
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great, thank you!
Since the main
branch is currently the v7 beta, I’ll release this manually on 6.x. I’ll do that until v7 is stable, then changesets creates release PRs that just need merging.
There may be a way to set that up with changesets, but also changesets has some existing bugs with how it versions monorepos so I also don’t trust it sometimes (e.g. since openapi-fetch depends on it, it gets confused and may bump a major version on that, too). But either way, it’s getting closer to v7 being stable so it’s just easier to do manually for a little longer.
Hey, this change has caused some issues for us Consider the changes to the digitial ocean snapshot (i think i'm marrying the correct part of the schema to the correct part of the snapshot). Their schema looks like this: anyOf:
- title: 'null'
type: object
nullable: true
description: If the floating IP is not assigned to a Droplet, the
value will be null.
- $ref: '../../droplets/models/droplet.yml' This PR resulted in this change to the snapshot: - droplet?: (Record<string, unknown> | null) | external["resources/droplets/models/droplet.yml"];
+ droplet?: unknown; I feel that We have the exact same construct throughout our schema: a (nullable) object OR [some model]. After this change, those types are now When slightly modifying the schema given in the original issue (#1407), to include openapi: 3.0.0
info:
title: example
version: 0.1.0
paths:
/my_route:
get:
responses:
'200':
description: 'Description'
content:
application/json:
schema:
$ref: '#/components/schemas/Test'
components:
schemas:
Test:
type: object
properties:
nullable_object_field:
type: object
nullable: true The following output is produced: Test: {
nullable_object_field?: unknown;
}; This does not seem correct. But using nullable_number_field:
type: number
nullable: true The following output is produced: Test: {
nullable_number_field?: number | null;
}; Which is correct. So I guess the logic may need refining? I think it makes sense to have a blanket |
A possible fix might be: if (schemaObject.nullable) {
if ("type" in schemaObject) {
finalType = tsUnionOf(finalType || "Record<string, unknown>", "null");
} else {
finalType = tsUnionOf(finalType || "unknown", "null");
}
} So using the old logic if there is a |
@davidleger95 just in case you missed the above comments. I'd be interested to hear your thoughts |
Changes
What does this PR change? Link to any related issue(s).
Fixes #1407
Correctly transform untyped nullable field to
unknown
instead ofRecord<string, unknown> | null
How to Review
How can a reviewer review your changes? What should be kept in mind for this review?
First PR, so are there any test cases I'm missing? Anything I should add? Anything I should keep in mind going forward?
Checklist
docs/
updated (if necessary)pnpm run update:examples
run (only applicable for openapi-typescript)