Skip to content

Property does not exist on type '{ [k in keyof addQuestionMarks]...' #995

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

Closed
mantysalo opened this issue Mar 3, 2022 · 8 comments
Closed
Labels
wontfix This will not be worked on

Comments

@mantysalo
Copy link

Hi, I'm not sure if this is a bug or if TypeScript just needs some more guidance but I'm having an issue with a generic function for generating schemas. Specifically the return type of the .parse() method

import { z } from "zod";

export const createSchema = <T extends z.ZodTypeAny>(schema: T) => {
  return z.object({
    foo: schema,
    bar: z.string()
  });
};

export const createHandler = <T extends z.ZodTypeAny>(
  schema: T,
  data: unknown
): void => {
  const eventSchema = createSchema(schema)
  const result = eventSchema.parse({foo: data, bar: 'baz'})
  console.log(result.foo) // Error!
  console.log(result.bar) // No error
};

createHandler(z.string(), 'hello');
createHandler(z.number(), 123);

The error that I'm getting on the console.log(result.foo) says:

Property 'foo' does not exist on type '{ [k_1 in keyof addQuestionMarks<{ foo: T["_output"]; bar: string; }>]: addQuestionMarks<{ foo: T["_output"]; bar: string; }>[k_1]; }'.ts(2339)

Here is a CodeSandbox with the same code as above.

https://codesandbox.io/s/nervous-banach-vkf8d5?file=/src/index.ts

@mantysalo
Copy link
Author

#153 (comment)

Found a solution here. Is this intended behaviour or a bug?

@FlorianWendelborn
Copy link
Contributor

I agree that this looks like a minor type bug. Personally, rather than changing the runtime behavior, I’d suggest overriding the types:

import { z } from "zod";

export const createSchema = <T extends unknown>(schema: z.ZodSchema<T>) => {
  return z.object({
    foo: schema,
    bar: z.string()
  });
};

export const createHandler = <T extends unknown>(
  schema: z.ZodSchema<T>,
  data: unknown
): void => {
  const eventSchema = createSchema(schema)
  const result = eventSchema.parse({foo: data, bar: 'baz'})
  console.log((result as unknown as {foo: T}).foo) // Error!
  console.log(result.bar) // No error
};

createHandler(z.string(), 'hello');
createHandler(z.number(), 123);

@corymharper
Copy link

Hi, I just wanted to add this small reproduction of the issue I made, I'm working around it right now:

https://codesandbox.io/s/angry-mcclintock-3wzhsf?file=/src/index.ts

@stale
Copy link

stale bot commented Jul 16, 2022

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@stale stale bot added the wontfix This will not be worked on label Jul 16, 2022
@lantw44
Copy link

lantw44 commented Jul 18, 2022

How can we remove the 'wontfix' label? It looks like a real bug. I end up working around it with code like this:

/**
 * While Zod explicitly documents the way to create a schema from a generic
 * function, it only works when the function is called with non-generic type
 * arguments. If it is called with generic types from a generic function,
 * properties using generic types may be wrongly removed from the output type,
 * causing TypeScript to report errors when accessing these properties.
 *
 * https://github.com/colinhacks/zod/issues/995
 *
 * This function provides a type-unsafe way to work around the issue. It uses
 * type assertion to silence the error when accessing data[key] and returns the
 * value with the type inferred from the schema. Since it doesn't check the data
 * object against the provided schema, this operation can be unsafe.
 *
 * Don't use the function if you can access the object normally.
 *
 * @param schema - Zod schema
 * @param data - Data object validated with the Zod schema
 * @param key - Property key to get the value
 * @returns - Property value
 */
function zodWorkAround<
  ZR extends zod.ZodRawShape,
  ZU extends 'passthrough' | 'strict' | 'strip',
  ZC extends zod.ZodTypeAny,
  Data extends Record<string, unknown>,
  Schema extends zod.ZodObject<ZR, ZU, ZC, Data, Data>,
  Key extends keyof Schema['shape'],
>(
  schema: Schema, data: Data, key: Key,
): zod.infer<Schema['shape'][Key]> {
  return (data as Record<Key, unknown>)[key];
}

const payload = schema.parse(unsafePayload);
const field = zodWorkAround(schema, payload, 'field');

@stale stale bot closed this as completed Jul 25, 2022
@FlorianWendelborn
Copy link
Contributor

@lantw44 @Stale should’ve removed it, but it seems to be misconfigured 😞

@lantw44
Copy link

lantw44 commented Aug 7, 2022

Should we reopen the issue, or I should open a new issue?

@FlorianWendelborn
Copy link
Contributor

@lantw44 if this issue still exists, you should submit a new issue and reference this issue in the description

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
wontfix This will not be worked on
Projects
None yet
Development

No branches or pull requests

4 participants