【问题标题】:using process.env in TypeScript在 TypeScript 中使用 process.env
【发布时间】:2017-12-24 23:07:38
【问题描述】:

如何在 TypeScript 中读取节点环境变量?

如果我使用process.env.NODE_ENV 我有这个错误:

Property 'NODE_ENV' does not exist on type 'ProcessEnv'

我已经安装了@types/node,但没有帮助。

【问题讨论】:

  • 你的 tsconfig 怎么样
  • 你使用的是什么版本的 TypeScript?从 2.2 开始,这应该是 work.
  • "打字稿": "^2.4.1"
  • 您能找到并向我们展示您正在使用的ProcessEnv 的定义吗?如果它是@Joe Clay 显示的DefinitelyTyped 定义,那么点符号应该可以工作(我无法在2.4 中重现您的错误)。
  • 同样的事情:export interface ProcessEnv { [key: string]: string |未定义}

标签: node.js typescript


【解决方案1】:

无法保证在 Node 进程中可以使用哪些(如果有的话)环境变量 - NODE_ENV 变量只是 Express 推广的约定,而不是 Node 本身内置的东西。因此,将它包含在类型定义中是没有意义的。相反,they define process.env like this:

export interface ProcessEnv {
    [key: string]: string | undefined
}

这意味着process.env 可以用字符串索引以获取字符串(或undefined,如果未设置变量)。要修复您的错误,您必须使用索引语法:

let env = process.env["NODE_ENV"];

另外,正如 jcalz 在 cmets 中指出的那样,如果您使用的是 TypeScript 2.2 或更新版本,您可以使用点语法访问上面定义的可索引类型 - 在这种情况下,您的代码应该按原样工作。

【讨论】:

  • 您可能想提一下,TypeScript 2.2 及更高版本允许使用点属性访问可索引类型。
  • @jcalz:嗯,我不知道,谢谢你的信息!
  • @jcalz 我正在使用 typescript 2.4.1,有什么办法可以使用它吗?虚线符号对我不起作用。
  • 在这里接受的答案是我写的一个模块 env-var。它将从 process.env 中读取变量并将它们从 string 强制转换为您需要的正确类型,例如 number。使用 TypeScript 2.2,您显然不需要 它,但它使 process.env 的工作更加简洁。
  • @EvanShortiss 感谢您提及该库。看起来不错。我在回答中也提到过。
【解决方案2】:

使用前只需添加process.env.NODE_ENV 跟随:

declare var process : {
  env: {
    NODE_ENV: string
  }
}

【讨论】:

  • 我不知道为什么会这样,但是谢谢!我采用了更通用的解决方案declare var process: { env: { [key: string]: string; } };
  • 谢谢,我把它放在了我的 mysqlConnection = createConnect 的上面我的 conection.ts 我命名了每个键:类型。像这样declare var process: { env: { HOST: string; USER: string; PASSWORD: string; DB: string; PORT: number; }; };
  • @Shakeel 因为声明合并而有效:typescriptlang.org/docs/handbook/…
【解决方案3】:

使用最新版本的打字稿执行后:

npm install --save @types/node

您可以直接使用process.env

console.log(process.env["NODE_ENV"])

如果您设置了NODE_ENV,您将看到预期的结果。

【讨论】:

  • 这是迄今为止最简单的替代方案。
  • 我试图找到一个解决方案 2 周...非常感谢
【解决方案4】:

您可以为此使用Type Assertion

有时您最终会遇到一种情况,即您会更多地了解某个 比 TypeScript 更有价值。通常,当您知道 某些实体的类型可能比其当前类型更具体。

类型断言是一种告诉编译器“相信我,我知道 我正在做。”类型断言就像其他语言中的类型转换, 但不执行数据的特殊检查或重组。它没有 运行时影响,并且纯粹由编译器使用。 TypeScript 假设 你,程序员,已经执行了你的任何特殊检查 需要。

例子

const nodeEnv: string = (process.env.NODE_ENV as string);
console.log(nodeEnv);

或者,您可能会找到更适合此特定目的的库,例如 env-var --

“使用正确类型在 node.js 中加载和清理环境变量的解决方案”

【讨论】:

  • 这是最好的答案。谢谢!
  • 这是我的案例中缺少的部分,已解决:TS2345: Argument of type 'string | undefined' is not assignable to parameter of type 'string'. Type 'undefined' is not assignable to type 'string'.
【解决方案5】:

在项目中安装 @types/node 后,您可以准确地告诉 TypeScript 您的 process.env 中存在哪些变量:

environment.d.ts

declare global {
  namespace NodeJS {
    interface ProcessEnv {
      GITHUB_AUTH_TOKEN: string;
      NODE_ENV: 'development' | 'production';
      PORT?: string;
      PWD: string;
    }
  }
}

// If this file has no import/export statements (i.e. is a script)
// convert it into a module by adding an empty export statement.
export {}

用法:

process.env.GITHUB_AUTH_TOKEN; // $ExpectType string

此方法将为您提供 IntelliSense,并且它还利用字符串文字类型。

注意:上面的sn-p是模块扩充。包含模块扩充的文件必须是 modules(相对于 scripts)。模块和脚本的区别在于模块至少有一个导入/导出语句。

为了使 TypeScript 将您的文件视为一个模块,只需向其添加一个导入语句。它可以是任何东西。即使export {} 也可以。

【讨论】:

  • 我在这里收到一个 TS 错误,“全局范围的增强只能直接嵌套在外部模块或环境模块声明中。”这是我在 CRA 应用程序中的react-app-env.d.ts 文件。对我来说,删除declare global 并在根目录下执行declare namespace NodeJS 是有效的。谢谢!
  • 这是因为只能在模块中进行扩充,而不能在脚本中进行。不同之处在于模块至少有一个导入/导出声明。为了克服这个问题,人们倾向于添加一个空的导入语句,只是为了让 TypeScript 将您的文件视为一个模块。类似import * as ts from 'typescript'
  • 事实证明,这不是必需的。我只需要删除declare global
  • 是的——它将适用于 Node.js 的当前类型,因为它们将 NodeJS 命名空间声明为全局。但不是每个图书馆都这样做,所以我认为建议通用解决方案会更好。
  • 你也可以export {}.
【解决方案6】:

1。创建一个.env 文件

# Contents of .env file
AUTHENTICATION_API_URL="http://localhost:4000/login"
GRAPHQL_API_URL="http://localhost:4000/graphql"

2。使用dotenv 将您的.env 文件加载到process.env

我们可以利用dotenv 设置特定于环境的process.env 变量。在您的src/ 目录中创建一个名为config.ts 的文件并按如下方式填充:

// Contents of src/config.ts

import {config as configDotenv} from 'dotenv'
import {resolve} from 'path'

switch(process.env.NODE_ENV) {
  case "development":
    console.log("Environment is 'development'")
    configDotenv({
      path: resolve(__dirname, "../.env.development")
    })
    break
  case "test":
    configDotenv({
      path: resolve(__dirname, "../.env.test")
    })
    break
  // Add 'staging' and 'production' cases here as well!
  default:
    throw new Error(`'NODE_ENV' ${process.env.NODE_ENV} is not handled!`)
}

注意: 这个文件需要被导入到你最顶层的文件中,可能是你的 src/index.ts 通过 import './config'放在所有其他进口)

3。检查 ENV 变量并定义 IProcessEnv

结合上述几个方法后,我们可以添加一些运行时检查以确保我们声明的IProcessEnv 接口反映了我们.env.* 文件中设置的ENV 变量。下面的内容也可以住在src/config.ts

// More content in config.ts
const throwIfNot = function<T, K extends keyof T>(obj: Partial<T>, prop: K, msg?: string): T[K] {
  if(obj[prop] === undefined || obj[prop] === null){
    throw new Error(msg || `Environment is missing variable ${prop}`)
  } else {
    return obj[prop] as T[K]
  }
}
// Validate that we have our expected ENV variables defined!
['AUTHENTICATION_API_URL', 'GRAPHQL_API_URL'].forEach(v => {
  throwIfNot(process.env, v)
})

export interface IProcessEnv {
  AUTHENTICATION_API_URL: string
  GRAPHQL_API_URL: string
}

declare global {
  namespace NodeJS {
    interface ProcessEnv extends IProcessEnv { }
  }
}
   

这将为我们提供适当的 IntelliSense/tslint 类型检查,以及在部署到各种环境时的一些理智。

注意这也适用于 ReactJS 应用程序(相对于 NodeJS 服务器应用程序)。您可以省略 步骤 (2),因为这是由 create-react-app 处理的。

【讨论】:

  • 很遗憾,TS 无法自动识别出您使用throwIfNot 保护了类型,因此仍然需要declare global。我仍然喜欢这种方法,并尝试了类似的方法。谢谢!
  • 我喜欢 throwIfNot() 作为通用实用程序的功能!
【解决方案7】:

对于任何来这里专门为 Create React App 项目寻找答案的人,您的变量名应该以 REACT_APP_ 开头

在此处阅读更多信息:https://facebook.github.io/create-react-app/docs/adding-custom-environment-variables

【讨论】:

  • 仅适用于 create-react-app。
  • 谢谢,我更新了答案。
【解决方案8】:

这是一个简短的函数,它保证将 process.env 值作为字符串提取——否则抛出错误。

对于更强大(但也更大)的东西,这里的其他人建议env-var

/**
 * Returns value stored in environment variable with the given `name`.
 * Throws Error if no such variable or if variable undefined; thus ensuring type-safety.
 * @param name - name of variable to fetch from this process's environment.
 */
export function env(name: string): string {
  const value = process.env[name];

  if (!value) {
    throw new Error(`Missing: process.env['${name}'].`);
  }

  return value;
}

然后您应该能够编写如下代码:

let currentEnvironment: string;
currentEnvironment = env('NODE_ENV');

【讨论】:

  • 漂亮干净,赞赏。
【解决方案9】:

您还可以使用类型保护功能。像这样的返回类型为

parameterName is string

例如

function isEnvVarSpecified(envVar: string | undefined): envVar is string {
  if(envVar === undefined || envVar === null) {
    return false;
  }
  if(typeof envVar !== 'string'){
    return false;
  }
  return true;
}

然后您可以将其称为类型保护:

function myFunc() {
  if(!isEnvVarSpecified(process.env.SOME_ENV_VAR')){
      throw new Error('process.env.SOME_ENV_VAR not found')
  }
  // From this point on the ts compiler won't complain about 
  // process.env.SOME_ENV_VAR being potentially undefined
}

【讨论】:

    【解决方案10】:

    只需对 process.env.YOUR_VAR 进行类型转换

    例子:

    mongoose
      .connect(String(process.env.MONGO_URL), {
        useNewUrlParser: true,
        useFindAndModify: false
      })
      .then(() => console.log('DB connected'))
      .catch((err: any) => console.error(err));
    

    【讨论】:

    • 这仍然不起作用,因为process 没有声明。
    【解决方案11】:

    对我有用的是,在任何我想使用process.env 的地方,我首先导入dotenv 并调用config()。另外,请记住在末尾附加!,并确保在您的.env 文件中定义了该属性

    import dotenv from 'dotenv';
    
    dotenv.config();
    
    export const YOUR_ATTRIBUTE = process.env.YOUR_ATTRIBUTE!;

    【讨论】:

    • 这是什么“!”签到真的可以吗?
    • @VadimSheremetov !用于告诉编译器该值不会未定义。例如,变量的类型可能是“string | undefined | null”。如果您尝试分配此变量,编译器将抱怨该值可能为 null 或未定义,因此添加 !您告诉编译器忽略或删除该检查,因为您已承担责任并将确保该值不是未定义的。所以打字稿不会对你大喊大叫,你可以轻松地运行你的程序。希望这有帮助
    【解决方案12】:

    补充之前的回复,经过一段时间处理这个问题,甚至安装了@types/node,我发现了这个answer。简而言之,只需运行一个重新加载窗口:

    "...但是,如果 typescript 语言服务器仍然使用以前版本的 tsconfig,您可能必须重新启动它。为了在 VS Code 中执行此操作,您可以执行 Ctrl+Shift+PReload WindowTypeScript: Restart TS server if可用...”

    【讨论】:

      【解决方案13】:

      在您的 typescript 项目中使用 node process.env 的最佳和最简单的方法是首先使用 tsc 编译,然后使用提供您的 ENV var 的 node 运行已编译的 javascript 文件。示例(首先确保tsconfig.ts 是您想要的输出目录也是编译文件的名称,我使用dist 作为输出目录和index.js 作为示例):

      cd my-typescriptproject
      tsc
      NODE_ENV=test node ./dist/index.js
      

      【讨论】:

        【解决方案14】:
        1. 通过运行npm i @types/node 安装@types/node
        2. "types": [ "node" ] 添加到您的 tsconfig.json 文件的 compilerSection 部分。

        【讨论】:

        • 在完成第 2 步之前,我浪费了很多时间。谢谢 Muhammad。
        【解决方案15】:

        这是我使用 envalid 的解决方案(在 Node.js 中验证和访问环境变量)

        import { str, cleanEnv } from 'envalid'
        
        const env = cleanEnv(process.env, {
          clientId: str(),
          clientSecret: str(),
        })
        
        // and now the env is validated and no longer undefined
        const clientId = env.clientId
        

        【讨论】:

          【解决方案16】:

          重要提示:如果您有一个网络应用程序并且您正在使用 webpack.DefinePlugin 在您的窗口上定义process.env,那么这些是您正在寻找的类型:

          declare namespace process {
              let env: {
                  // this is optional, if you want to allow also
                  // other values than the ones listed below, they will have type 
                  // string | undefined, which is the default
                  [key: string]: string
                  commit_hash: string
                  build_time: string
                  stage: string
                  version: string
                  // ... etc.
              }
          }
          

          【讨论】:

            【解决方案17】:

            我知道这将有助于搜索此内容但找不到简单答案的人为什么您的 proccess.env 变量会让您的编译器发牢骚:

            安装@types/node:

            npm i @types/node
            

            然后,无论您将环境作为字符串包含在何处,请执行以下操作:

            process.env.YOUR_ENV ?? ''
            

            双问号允许您检查空/未定义。

            【讨论】:

              【解决方案18】:

              我写了一个模块来简化这个。它没有依赖项,因此相当轻量级。它也适用于 dotenv,如果需要,您可以将自定义 process.env 传递给 env.from 函数。

              已经在一些答案中提到过,但这里有一个例子:

              使用 yarn/npm 安装它:

              npm install env-var --save
              

              然后读取变量:

              import * as env from 'env-var'
              
              // Read NODE_ENV and verify that:
              // 1) it is set using the required() function
              // 2) it is either 'dev' or 'prod'
              // 3) throw a runtime exception if conditions #1 or #2 fail
              const environment = env.get('NODE_ENV').required().asEnum(['dev', 'prod'])
              
              // Intellisense will suggest 'dev' or 'prod'
              if (environment === 'dev') {
                console.log('yep, this is dev')
              } else {
                console.log('looks like this is prod')
              }
              

              或者其他:

              import { get } from 'env-var'
              
              // Read the GitHub token. It could be undefined
              const githubToken = get('GITHUB_TOKEN').asString()
              
              // Read MAX_CONCURRENCY, or default to 5. Throw an error if it's
              // not set to a positive integer value
              const concurrencyLimit = get('MAX_CONCURRENCY').default(5).asIntPositive()
              
              function callGitApi (token: string, concurrency: number) { /* implementation */ }
              
              // TS Error: Argument of type 'string | undefined' is not assignable to
              // parameter of type 'string'.
              callGitApi(githubToken, concurrencyLimit)
              

              【讨论】:

                猜你喜欢
                • 2018-04-11
                • 2022-08-09
                • 1970-01-01
                • 2021-12-02
                • 2019-09-16
                • 2018-10-02
                • 1970-01-01
                • 2018-09-04
                • 1970-01-01
                相关资源
                最近更新 更多