#Return type based on const type argument doesn't work with zod schema

15 messages · Page 1 of 1 (latest)

undone goblet
#

I have this kind of function: ```ts
const fieldTypeToSchema = </* const */ T extends ZodField>(field: T): z.ZodSchema<FieldValueType<T>> => {
if (field.type === "text") return z.string()
if (field.type === "url") return z.string().url()
if (field.type === "password") return z.string()
if (field.type === "email") return z.string().email()
if (field.type === "color") return z.string().regex(/#[\da-fA-F]{6}/)

return z.never()
}

(i added the `const` in a comment since it breaks discord highlighting)

but i get this error on every return: ```
Type 'ZodString' is not assignable to type 'ZodType<FieldValueType<T>, ZodTypeDef, FieldValueType<T>>'.
  Types of property '_type' are incompatible.
    Type 'string' is not assignable to type 'FieldValueType<T>'.

The ZodField type is a discriminated union, wherein each member has a schema field ((z.Schema) => z.Schema) and a type field.

the FieldValueType<T> type takes in a ZodField and returns the actual typescript type its schema returns (FieldValueType<{ type: "text" }> => string, FieldValueType<{ type: "number" }> => number, etc)

why does this not work the way i expect it to? shouldn't the type narrowing via the if statement tell TS that FieldValueType<T> is now the right type for the field?

types.ts: https://gist.github.com/TheOnlyTails/154a8a3eab6adae3a3721dfe6fcf8021
createForm.ts: https://gist.github.com/TheOnlyTails/fcd7ea53a40b55bce54399ce94df8c2e

near hamlet
#

That narrowing only has an effect on the type of field, it does not affect the entire T type

undone goblet
#

hm, how would i make it affect all of T?

#

using typeof field in the return type doesn't do anything

near hamlet
#

You can't

#

The way flow types (= control flow analysis) works is every identifier gets an extra type, the "flow type" at every node in the "flow tree"

#

There is some extra processing to keep track of e.g. discriminated unions, but the narrowed type calculated for field is a different type than the original T.

#

You can work around it a bit with a single signature overload:

undone goblet
#

hmm, looks like it works

#

if you wouldn't mind explaining, why does it work?

#

ah, nvm, i see

#

what i originally wanted is validation that it actually returns the correct schema type based on the field type

#

and that's not longer there

#

i guess i'm trying to do typescript wizardry that isn't really possible