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

generic Omit function breaks type inferance #3826

Open
JaeTLDR opened this issue Oct 31, 2024 · 2 comments
Open

generic Omit function breaks type inferance #3826

JaeTLDR opened this issue Oct 31, 2024 · 2 comments

Comments

@JaeTLDR
Copy link

JaeTLDR commented Oct 31, 2024

When using a function to omit shared keys among many schemas z.infer nolonger exports the underlying types correctly

import { z } from "zod";

const metaKeys = {
    _rid: z.string(),
    _self: z.string(),
    _etag: z.string(),
    _attachments: z.string(),
    _ts: z.string(),
};

function omitMetaKeys(schema: z.AnyZodObject): z.AnyZodObject {
    return schema.merge(z.object({...metaKeys})).omit(Object.keys(metaKeys).reduce((prev, curr) => { return { [curr]: true, ...prev } }, {}));
}

export const mySchema = z.object({
    id: z.string(),
});
export interface myType extends z.infer<typeof mySchema> {}
// works correctly complaining about the missing id property
const eg:myType ={}

export const myOmitSchema = omitMetaKeys(z.object({
    id: z.string(),
}));
export interface myOmitType extends z.infer<typeof myOmitSchema> {}
//does not complain, whihc is incorrect behaviour
const egOmit:myOmitType ={} 
image

if we use the same schema and remove the call to omitMetaKeys, we gain typing within vscode

image
@m10rten
Copy link
Contributor

m10rten commented Nov 3, 2024

Hi,
My first thought is that it 'breaks' because you are returning z.AnyZodObject, and not a generic T extends AnyZodObject.

if you would change it into:

function omitMetaKeys<T extends z.AnyZodObject>(schema: T): Omit<z.infer<T>, 'key_a' | 'key_b'> {
    return schema.merge(z.object({...metaKeys})).omit(Object.keys(metaKeys).reduce((prev, curr) => { return { [curr]: true, ...prev } }, {}));
}

Then I believe it should work.

Try to extract the keys from your metadata, then you can use that in the Omit TS generic type.

@JaeTLDR
Copy link
Author

JaeTLDR commented Nov 6, 2024

Thanks this seems to be much closer, your code didn't seem to work for me, but the below did, however i am not sure how 'good' it is in comparison in terms of typescript correctness.

function omitMetaKeys<T extends z.AnyZodObject>(schema: T): T {
    return schema.merge(z.object({...metaKeys})).omit(Object.keys(metaKeys).reduce((prev, curr) => { return { [curr]: true, ...prev } }, {})) as T;
}

further suggestions are very welcome,

Thanks again

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

2 participants