-
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
optional should not add undefined to type signature #3186
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
Comments
ill try to fix this issue please |
thanks for explaining let me fix it |
@JacobWeisenburger I'm not sure I follow, what's your point here? It seems you've disabled |
Here's my {
"compilerOptions": {
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"module": "esnext",
"target": "esnext",
"moduleResolution": "bundler",
"moduleDetection": "force",
"allowImportingTsExtensions": true,
"noEmit": true,
"composite": true,
"strict": true,
"downlevelIteration": true,
"skipLibCheck": true,
"jsx": "preserve",
"allowSyntheticDefaultImports": true,
"forceConsistentCasingInFileNames": true,
"allowJs": true,
"types": [
"bun-types"
]
},
"include": [
"src/**/*",
"package.json"
]
} |
yeah? The default is Imho this isn't an enhancement but a bug - zod "deliberately" add's implicit nullability even if that nullability is explicitly forbidden. From what I'm reading from other issues in this repo I'm fairly certain that this is not what zod wanted or intended. fyi: |
i understood the problem and i also looked after the source code and understood what's wrong |
Who exactly are you asking for permission? It's github, just create a PR?
…On Mon, Jan 29, 2024, 03:03 Tahsin Ayman ***@***.***> wrote:
i understood the problem and i also looked after the source code and
understood what's wrong
let me try to fix it
—
Reply to this email directly, view it on GitHub
<#3186 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/ACOHZTWSPGHW7H5UKTYYV5DYQ37NHAVCNFSM6AAAAABCJTIF62VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTSMJTHAZTSMRZGQ>
.
You are receiving this because you authored the thread.Message ID:
***@***.***>
|
sorry im just a beginner. |
the more I look at this, the more it looks like this won't be possible without a breaking change. While I did get correct optional inference working (basically just switch Removing that assumption breaks other tests because optional can't depend on its wrapping context. E.g. here const stringSchema = z.string().optional();
const objectSchema = z.object({
foo: stringSchema
});
type S = z.infer<typeof stringSchema> // expectation: string | undefined
type O = z.infer<typeof objectSchema> // expectation: { foo?: string } Since the stringschema can't know when it's being used in an object context it's impossible to correctly represent optional keys without also making the value "undefinedable". Imho the only true solution (and maybe even the right one) would be to strictly reserve @colinhacks , sorry for directly mentioning you but do you see any other solution? |
🔥 I also tried but it didn't seem to make any sense to me 👎🏻 |
what i have come to notice when contributing is the class ZodOptional<T extends ZodTypeAny> extends ZodType<
T["_output"] | undefined,
ZodOptionalDef<T>,
T["_input"] | undefined
> if you remove the |
@colinhacks nothing seems to be working. and is there any source code docs. and there is no comment / docs in the codebase!!! 👎🏻 |
@TahsinAyman it's their prerogative not to consider this issue and they're under no obligation to write the codebase in any other way than it is now. Honestly, if zod were my project I'd close this issue since
If people then started to complain about how my codebase doesn't cater to somebody elses taste I'd be less than willing to see their point. For me it just meant sticking closer to FP patterns and using it like this: z.object({
foo: z.string().optional().transform(option.fromNullable)
}) |
@hesxenon can you expand on your workaround please? Where does |
@sp88011 it comes from fp-ts' implementation of the option monad. Since ZodObject makes each key optional where the value contains undefined (which is wrong) all you hav 8000 e to do is transform the value to something that does not include undefined after the optional codec. |
I found a work arround in whitch you can make it a nullable too and when the type is infered the null is added as a type incase thats what you nedded
|
I have been bitten by this problem recently. Here's a simplified version of the use case I have: type Entity = {
name: string;
description?: string;
};
const EntityCreationRequest = z.object({
name: z.string(),
description: z.string().optional(),
});
const entity: Entity = EntityCreationRequest.parse({
name: "hi there",
}); The parse call above issues the following compiler error:
This is because the schema accepts a present, On one hand, Zod's notion of optionality belongs to the schema of the value itself, whereas the optionality in typescript is in the relationship between an object key and a value, so the current behavior doesn't seem completely wrong to me in this specific case, but it does feel wrong when applying I guess the only non-breaking fix would be to introduce a new type of optionality, attached to the object key itself and have that behave differently, which would probably require changes to Unfortunately I'm not aware of a workaround at this moment. |
I encountered the same, did you manage to figure out how to get it fixed? |
This is particularly annoying when using const patchUserSchema = createInsertSchema(user).omit({ id: true }).partial() will result in types that are incompatible with drizzle itself. (The same happens when extending with Here's the workaround we had been using for some time (before disabling type RemoveUndefined<T> = {
[K in keyof T]: Exclude<T[K], undefined>
}
export const removeUndefinedProps = <T extends object>(obj: T) => {
return Object.entries(obj).reduce((acc, [key, value]) => {
if (value !== undefined) acc[key as keyof T] = value
return acc
}, {} as RemoveUndefined<T>)
}
// ... later in the schema definition
const patchUserSchema = createInsertSchema(user)
.omit({ id: true })
.partial()
.transform(removeUndefinedProps) |
This point is completely valid, but it would be nice to at least get the thoughts of one of the maintainers - although again, it is their prerogative to respond. Perhaps they are aware of a more generic workaround. I tried @acontreras89 's solution but I'm not having much luck.
As for it being a breaking change, just thinking out loud, but would the impact of fixing this issue actually negatively impact most end users? I imagine the majority of users that are affected by this change are indeed using |
This issue is also affecting us. We are using a library that expects type signatures like:
And there is no way to infer that type from a Zod schema. The Perhaps, for a non-breaking way to resolve this issue, the |
This will be implemented in Zod 4 (currently in beta). See the announcement. |
@BrendanC23 How you can get this definition using Zod 4? type Schema = {
foo?: string
} |
I'm sorry if this is a duplicate, I could not find an existing issue or discussion that seemed to be exactly about the following. It's really rather simple: the following schema infers the wrong type
is inferred as
when it should really be
Let me showcase the issue with two different typescript playgrounds. They both have the same content, but the second has
exactOptionalPropertyTypes
enabled.exactOptionalPropertyTypes: false
This playground errors, because even though we know that
foo
exists onresult
the compiler addsundefined
to the set of possible types forresult.foo
.exactOptionalPropertyTypes: true
And here we eliminated the error, because the compiler knows that if
foo
exists onresult
it must be exactly astring
.The problem to note here is that the decision to include
undefined
should be up to the compiler. Zod takes that decision away and subsequently makes it impossible to truly express optional keys.The text was updated successfully, but these errors were encountered: