colinhacks / zod

TypeScript-first schema validation with static type inference
https://zod.dev
MIT License
31.66k stars 1.1k forks source link

schema.shape[key].parse(value) not infering correctly when typeof key is a key of the schema. #2537

Open Eyon42 opened 1 year ago

Eyon42 commented 1 year ago

This is what happens: image

A workaround (besides using the generic to manually set type) is using pick and then getting the value using the key: image

But either way it's not expected behaviour.

Code example:

import { prisma } from "@/prisma";
import { z } from "zod";

const globalSettingsSchema = z.object({
  fee: z.number(),
  hello: z.string().optional(),
});
export type globalSchemaType = z.infer<typeof globalSettingsSchema>;

export async function getSetting<K extends keyof globalSchemaType>(key: K) {
  const setting = await prisma.globalSettings.findUniqueOrThrow({
    where: {
      key,
    },
  });
  const parsedValue = JSON.parse(setting.value);
  // const result = globalSettingsSchema.pick({ [key]: true }).parse(parsedValue);
  // return result[key];
  const result = globalSettingsSchema.shape[key].parse(parsedValue);
  return result //as globalSchemaType[K];
}
JacobWeisenburger commented 9 months ago

I have simplified the example to make it easier to diagnose. This seems like a bug, but it could also be a limitation of TypeScript.

const schema = z.object( { foo: z.number(), bar: z.string() } )
type Data = z.infer<typeof schema>

function someFn1<K extends keyof Data> ( key: K ) {
    return schema.pick( { [ key ]: true } ).parse( 'anything' )[ key ]
}
someFn1( 'foo' ) // : number
someFn1( 'bar' ) // : string

function someFn2<K extends keyof Data> ( key: K ) {
    return schema.shape[ key ].parse( 'anything' )
}
someFn2( 'foo' ) // : string | number
someFn2( 'bar' ) // : string | number

Is someone else able to explain what is happening here?

Brandontam29 commented 1 month ago

I have the same issue.