t3-oss / t3-env

https://env.t3.gg
MIT License
2.67k stars 86 forks source link

`createEnv` from `@t3-oss/env-nextjs` returns genric object when using Zod v3.23.0 #222

Closed mwskwong closed 5 months ago

mwskwong commented 5 months ago

After upgrading Zod to v3.23.0 from v3.22.5, createEnv from @t3-oss/env-nextjs will always return

const env: Readonly<{
    [x: string]: any;
}>

regardless of how the env vars are specified. The createEnv exported from @t3-oss/env-core doesn't seem to be affected by this issue.

Reproduction: Edit t3-env-zod-v3.23.0-compatibility

import { createEnv } from "@t3-oss/env-nextjs"; // this doesn't generate the correct type
// import { createEnv } from "@t3-oss/env-core"; // this does
import { z } from "zod"; // reproducable in v3.23.0. Not reproducible in v3.22.5

const env = createEnv({
  server: {
    DATABASE_URL: z.string().url(),
  },
  experimental__runtimeEnv: {},
});

console.log(env);

Hover the env variable to see the generated type.

Stewart86 commented 5 months ago

Same, just got a failed check with dependabot for Zod version bump. Following for resolution.

waltershewmake commented 5 months ago

Also experiencing this

shadizx commented 5 months ago

same, but i'm experiencing this with older zod versions as well.

juliusmarminge commented 5 months ago

Someone know what types they've changed? We're not using any internal types so feels like they've unintentionally broken semver.

same, but i'm experiencing this with older zod versions as well.

That's weird, please open a separate issue with a reproduction.

mwskwong commented 5 months ago

@juliusmarminge Could it be related to this change? image

juliusmarminge commented 5 months ago

@juliusmarminge Could it be related to this change? image

we're only using ZodType as a generic constraint so that shouldn't matter

juliusmarminge commented 5 months ago

can't reproduce inside this repo though which will make it harder to debug... CleanShot 2024-04-22 at 10 08 42@2x

mwskwong commented 5 months ago

can't reproduce inside this repo though which will make it harder to debug... CleanShot 2024-04-22 at 10 08 42@2x

Interesting. Since there have been a few commits since the last release, maybe one of the commits "solves" unintentionally (e.g. the "bump deps" one, which is doing more than just bumping deps)?

Is it feasible to release a beta/canary/unstable release so that we can test it and see whether that's the case?

juliusmarminge commented 5 months ago

Is it feasible to release a beta/canary/unstable release so that we can test it and see whether that's the case?

Was just about to do that from #223

juliusmarminge commented 5 months ago

Try this one: pnpm add @t3-oss/env-nextjs@0.9.3-canary.b0cc17a

Stewart86 commented 5 months ago

yup looks like canary fixes it for me

mwskwong commented 5 months ago

Same for me.

Though there is a breaking change on presets, which are now functions

juliusmarminge commented 5 months ago

Though there is a breaking change on presets, which are now functions

Yea this will be a 0.10 release. Needed to make them functions to avoid side-effects in the imports

I'll go ahead and relese 0.10 now then

colinhacks commented 5 months ago

Thanks for the quick action @juliusmarminge.

I've fixed the underlying problem in Zod 3.23.2, so there's no need for everyone to upgrade. Perhaps add this as a note at the top of the original issue to avoid further confusion?


Notes for those who are so inclined:

Because createEnv in t3env/next lacks an explicit return type annotation, TypeScript generates one for the .d.ts. To do so, it pulls in some internal Zod utilities (namely objectUtil.addQuestionMarks) from whatever version of Zod was installed when the build happened. You can see this in this snippet of the declaration file:

declare function createEnv<
    TServer extends Record<string, ZodType> = NonNullable<unknown>,
    TClient extends Record<
        `${ClientPrefix}${string}`,
        ZodType
    > = NonNullable<unknown>,
    TShared extends Record<string, ZodType> = NonNullable<unknown>,
    const TExtends extends Array<Record<string, unknown>> = [],
>(
    opts: Options<TServer, TClient, TShared, TExtends>,
): Readonly<
    (zod.objectUtil.addQuestionMarks<
        zod.baseObjectOutputType<TServer>,
        {
            [k_1 in keyof zod.baseObjectOutputType<TServer>]: undefined extends zod.baseObjectOutputType<TServer>[k_1]
                ? never
                : k_1;
        }[keyof TServer]
    > extends infer T_25
        ? {
                [k in keyof T_25]: zod.objectUtil.addQuestionMarks<
                    zod.baseObjectOutputType<TServer>,
                    {
                        [k_1 in keyof zod.baseObjectOutputType<TServer>]: undefined extends zod.baseObjectOutputType<TServer>[k_1]
                            ? never
                            : k_1;
                    }[keyof TServer]
                >[k];
            }
        : never) 
        // ...
 >  

This essentially means that that dependency on Zod is no longer "portable" and requires a specific version of Zod to work properly.

Normally compiling something like this with tsc would throw an error like the one below. I'm currently seeing this error for the nuxt package but not the nextjs one when building the packages locally 🤷‍♂️ I'm still not sure why.

@t3-oss/env-nuxt:build: src/index.ts(19,17): error TS2742: The inferred type of 'createEnv' cannot be named without a reference to '@t3-oss/env-core/node_modules/.pnpm/zod@3.23.0/node_modules/zod'. This is likely not portable. A type annotation is necessary.

The utility type zod.objectUtil.addQuestionMarks changed from accepting two generics to accepting a single generic. Because the 3.22.x version of this utility had leaked into the declaration file for t3env@0.9.2, the typings for t3-env broke when used in conjunction with zod@3.23.0.

My fix was to add a second generic argument back to that type (a no-op): https://github.com/colinhacks/zod/commit/ef588d036f3e98b832796e9a681dbaf097631ea0

I think an explicity return type on createEnv would future-proof the library. I made a PR to that effect: https://github.com/t3-oss/t3-env/pull/224

I'll also see if there's something I can do on my size to prevent Zod utilities from getting "inlined" like this in the future.


Unrelated, there's also some kind of recursive unrollling happening due to Reduce<> that blows up the index.d.ts file. This is also fixed by my PR. (But it's unrelated to this issue.)

arekbartnik commented 5 months ago

@t3-oss/env-nextjs: 0.9.1 with zod: 3.23.4 (latest) -> works @t3-oss/env-nextjs: 0.10.1 (latest) with zod: 3.23.4 (latest) -> shows any

vaunblu commented 5 months ago

3-oss/env-nextjs: 0.9.1

I also get this issue. Reverting to 0.9.1 fixes the issue for now

ixuz commented 4 months ago

Still a problem for me.

Using: @t3-oss/env-nextjs: 0.10.1 with zod: 3.23.8 and the createEnv returns any type.

bastibuck commented 4 months ago

@juliusmarminge I can confirm this issue still persists like described above. Rolling back to 0.9.1 works for now

juliusmarminge commented 4 months ago

If anyone still gets this please also provide a reproduction. Im using the latest version without issues

bastibuck commented 4 months ago

When I install 0.10.1 it says

Cannot find module '@t3-oss/env-nextjs' or its corresponding type declarations.

Using version 0.9.1 it works fine.

See https://codesandbox.io/p/devbox/dreamy-black-7l4ywn?workspaceId=78150bbe-056c-4c8d-8542-1698ecfb6c1d

juliusmarminge commented 4 months ago

When I install 0.10.1 it says

Cannot find module '@t3-oss/env-nextjs' or its corresponding type declarations.

Using version 0.9.1 it works fine.

See https://codesandbox.io/p/devbox/dreamy-black-7l4ywn?workspaceId=78150bbe-056c-4c8d-8542-1698ecfb6c1d

You're using an incompatible module resolution. See https://github.com/t3-oss/t3-env#installation for compatible options

CleanShot 2024-05-30 at 13 57 43@2x

bastibuck commented 4 months ago

Ahhh I see. After I changed it to

    "moduleResolution": "Bundler",
    "module": "esnext",

it seems to work.

Also I had to use proper import instead of require inside my next.config.mjs. Maybe this helps anyone else finding this