lostfictions / znv

Type-safe environment parsing and validation for Node.js with Zod schemas
https://github.com/lostfictions/znv
MIT License
349 stars 6 forks source link

The inferred type cannot be named without a reference to '../node_modules/znv/dist/util'. #12

Open adicco opened 10 months ago

adicco commented 10 months ago

Hello there,

The following code:

import { parseEnv } from 'znv';
import { z } from 'zod';

export const {
  DEFAULT_ADMIN_EMAILS,
 } = parseEnv(process.env, {
   DEFAULT_ADMIN_EMAILS: z
    .string()
    .optional()
    .transform((val) => {
      return val ? val.split(',') : [];
    }),
 });

yields the following TypeScript warning:

The inferred type of 'DEFAULT_ADMIN_EMAILS' cannot be named without a reference to '../node_modules/znv/dist/util'. This is likely not portable. A type annotation is necessary. 

Has anyone encountered the same thing? Not really sure how to fix this. I am using Bun. My tsconfig:


{
  "compilerOptions": {

    "lib": ["ESNext"],
    "module": "esnext",
    "target": "esnext",
    "moduleResolution": "bundler",
    "noEmit": true,
    "allowImportingTsExtensions": true,
    "moduleDetection": "force",

    "jsx": "react",
    "jsxFactory": "Html.createElement",
    "jsxFragmentFactory": "Html.Fragment",
    "baseUrl": "./src",

    "paths": {
      "~/*": ["./src/*"]
    },

    "types": [
      "bun-types",
      "typed-htmx"
    ],

    "allowJs": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "skipLibCheck": true,
    "composite": true,
    "downlevelIteration": true,
    "allowSyntheticDefaultImports": true
  }
}

Thank you!

lostfictions commented 10 months ago

Hi there. Does this problem reproduce for you using Node and npm (or yarn or pnpm) instead of Bun?

If yes, could you share a minimal reproduction project? Ideally one that doesn't include any source files besides the one you've included here and that only depends on znv and zod (and typescript).

cometkim commented 10 months ago

I can see the same error when I use moduleResolution: "Bundler" on the specific workspace of a monorepo.

I added the same moduleResolution for the project (root), then the error disappear.

lostfictions commented 10 months ago

Please share a minimal reproduction repo if you can! I'm unlikely to be able to diagnose the problem without being able to investigate the specific circumstances under which it occurs.

lostfictions commented 10 months ago

Tagging @BowlingX who added ES Modules support, just in case it's related

BowlingX commented 10 months ago

I can have a look, did not encounter the issue yet.

cometkim commented 10 months ago

https://github.com/microsoft/TypeScript/issues/47663

BowlingX commented 10 months ago

I'm unable to reproduce the issue with "moduleResolution": "bundler" in a mono repo. But it sounds like you might have multiple versions of znv installed. You can e.g. check with yarn why znv if this assumption is correct. As @cometkim already wrote, you can solve this issue by using the moduleResolution field, and/or make sure that all your packages refer to the same version.

cometkim commented 10 months ago

But it sounds like you might have multiple versions of znv installed.

I have exactly one znv instance.

And after changing module / moduleResolution to NodeNext it happens again consistently. Frankly, I'm not even sure Bundler solves the problem. This suddenly disappears and reappears in my editor. I also tried reproducing it in a small repository, but it didn't show up... yet trying

One thing worth noting is that this error does not occur with the tsc command, but only appears in the editor. This may be a bug in tsserver.

What's annoying is that I can't ts-ignore this as mentioned in the upstream issue 😢

BowlingX commented 10 months ago

Is it possible that you have different typescript versions?

cometkim commented 10 months ago

No, I have only one typescript with same version and hash

mamlzy commented 3 months ago

facing the same issue, any updates?

// tsconfig.json
{
  "$schema": "https://json.schemastore.org/tsconfig",
  "display": "Default",
  "compilerOptions": {
    "composite": false,
    "declaration": true,
    "declarationMap": true,
    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true,
    "inlineSources": false,
    "isolatedModules": true,
    "module": "NodeNext",
    "moduleResolution": "NodeNext",
    "noUnusedLocals": false,
    "noUnusedParameters": false,
    "preserveWatchOutput": true,
    "skipLibCheck": true,
    "strict": true,
    "paths": {
      "@/*": ["./src/*"]
    }
  },
  "include": ["src/**/*.ts", "./*.js", ".eslintrc.cjs"],
  "exclude": ["node_modules"]
}
// env.ts
import { parseEnv, z } from 'znv';

export const env = parseEnv(process.env, {
  NODE_ENV: z.enum(['development', 'production']),
  PORT: z.number(),
  ACCESS_TOKEN_EXPIRATION: z.number().optional(),
});
lostfictions commented 3 months ago

Hey there, per this issue comment on the TypeScript repo and the comment directly preceding it, it appears that in some situations this may be a bug that could be fixed in the upcoming TypeScript 5.5 release. Maybe you could try the 5.5 beta to see if it fixes your problem? (See also the relevant section of the 5.5 beta release notes.)

Failing that, the TypeScript devs have written up a more detailed explanation of some of the (legitimate) manifestations of this error message here: https://github.com/microsoft/TypeScript/pull/58176#issuecomment-2052698294 I'm not sure if this is actionable on the part of znv, but if it is I'm happy to revisit this after the TS 5.5 release. As far as I know znv correctly expresses a peer dependency on zod, and if you have installed both then things should work ok. I know certain package managers have some implicit handling of peer dependencies that may make things strange -- I'd recommend trying to manually install zod alongside znv and to check your package manager's console output for any warnings about peer dependencies.

gyf304 commented 2 months ago

@lostfictions I believe this can be resolved by adding export type * from "./util.js" to index.ts.

Typescript can only reference types explicitly exported in package.json.

The types returned by parseEnv, e.g. (DeepReadonly) is not reachable from the declared entrypoints in package.json.