Skip to content
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

Typing for record became too loose after addition of Partial #992

Closed
hsarokina-ita opened this issue Mar 2, 2022 · 4 comments
Closed

Typing for record became too loose after addition of Partial #992

hsarokina-ita opened this issue Mar 2, 2022 · 4 comments

Comments

@hsarokina-ita
Copy link

This issue is related to: #751

After updating zod version from v3.12.0 to v3.13.3 we started to receive the following TS error: error TS2322: Type 'Partial<Record<string, string>>' is not assignable to type 'Record<string, string>'. 'string' index signatures are incompatible. Type 'string | undefined' is not assignable to type 'string'. Type 'undefined' is not assignable to type 'string'.

We are using zod record with string keys and values. I think that returning Partial for string records is a bug, because we are sure, that all keys that record has are checked by zod and contain non-undefined value, but TS says that they can contain undefined that forces us to do extra checks in the later code to convince TS that all values are strings.

I've created a repo with simple reproduction to illustrate such use case better:
https://github.com/hsarokina-ita/zod-partial-record
safeParse returned success: false for object with undefined values, this means that zod checked for it to be defined. But at the same time I can assign record with undefined value to typing returned by parser.

@amuttsch
Copy link

amuttsch commented Mar 2, 2022

I have a similar issue with a string key, but my value is not a string but a z.union of some objects. I don't want my record value to be optional, this seems to be contradictionay to the "everything is required until .optional() is called".

@colinhacks
Copy link
Owner

This was changes to more accurately reflect the type Zod actually validates. Zod can't do exhaustiveness checking - for instance it doesn't/can't verify that all elements of the enum show up as keys:

z.record(z.enum(['a', 'b', 'c']), z.string());
// => Record<'a' | 'b' | 'c', string>

This is inaccurate - Zod merely validates each key against the key schema, but can't guarantee that all three keys exist in the object. So a more accurate type is Partial<Record<'a' | 'b' | 'c', string>>.

But your right that wrapping in Partial was too permissive. Just updated the typings:

z.record(z.string, z.string);
// Record<string,string>;

z.record(z.enum(['a', 'b', 'c']), z.string());
// => Partial<Record<'a' | 'b' | 'c', string>>

Merged in 3.13.3.

@alexanderhorner
Copy link

This still seems to be happening when using custom string literal types.

export const UUIDSchema = z.string().uuid() as z.ZodType<UUID>;

When defining a record with UUIDSchema as key, it will be Partial.

@AlexErrant
Copy link

AlexErrant commented Dec 19, 2024

@alexanderhorner Looking at the source code, you should put UUID in a Brand to prevent Partial.

Edit: actually no, you may need to wait until this PR is merged: #3918

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants