How do I read node environment variables in TypeScript?
If i use process.env.NODE_ENV I have this error :
Property 'NODE_ENV' does not exist on type 'ProcessEnv'
I have installed @types/node but it didn't help.
Once you have installed @types/node in your project, you can tell TypeScript exactly what variables are present in your 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 {}
Usage:
process.env.GITHUB_AUTH_TOKEN; // $ExpectType string
This method will give you IntelliSense, and it also takes advantage of string literal types.
Note: the snippet above is module augmentation. Files containing module augmentation must be modules (as opposed to scripts). The difference between modules and scripts is that modules have at least one import/export statement.
In order to make TypeScript treat your file as a module, just add one import statement to it. It can be anything. Even
export {}will do.
react-app-env.d.ts file in a CRA app. For me, removing the declare global and doing declare namespace NodeJS at root worked. Thanks!import * as ts from 'typescript'.declare global.export {}.There's no guarantee of what (if any) environment variables are going to be available in a Node process - the NODE_ENV variable is just a convention that was popularised by Express, rather than something built in to Node itself. As such, it wouldn't really make sense for it to be included in the type definitions. Instead, they define process.env like this:
export interface ProcessEnv {
[key: string]: string | undefined
}
Which means that process.env can be indexed with a string in order to get a string back (or undefined, if the variable isn't set). To fix your error, you'll have to use the index syntax:
let env = process.env["NODE_ENV"];
Alternatively, as jcalz pointed out in the comments, if you're using TypeScript 2.2 or newer, you can access indexable types like the one defined above using the dot syntax - in which case, your code should just work as is.
just add before use process.env.NODE_ENV follow lines:
declare var process : {
env: {
NODE_ENV: string
}
}
declare var process: { env: { [key: string]: string; } };declare var process: { env: { HOST: string; USER: string; PASSWORD: string; DB: string; PORT: number; }; };You can use a Type Assertion for this
Sometimes you’ll end up in a situation where you’ll know more about a value than TypeScript does. Usually this will happen when you know the type of some entity could be more specific than its current type.
Type assertions are a way to tell the compiler “trust me, I know what I’m doing.” A type assertion is like a type cast in other languages, but performs no special checking or restructuring of data. It has no runtime impact, and is used purely by the compiler. TypeScript assumes that you, the programmer, have performed any special checks that you need.
Example
const nodeEnv: string = (process.env.NODE_ENV as string);
console.log(nodeEnv);
Alternatively you might find a library such as env-var more suitable for this specific purpose --
"solution for loading and sanitizing environment variables in node.js with correct typings"
TS2345: Argument of type 'string | undefined' is not assignable to parameter of type 'string'. Type 'undefined' is not assignable to type 'string'..env file# Contents of .env file
AUTHENTICATION_API_URL="http://localhost:4000/login"
GRAPHQL_API_URL="http://localhost:4000/graphql"
.env file into process.env with dotenvWe can leverage dotenv to set environment-specific process.env variables. Create a file called config.ts in your src/ directory and populate as follows:
// 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!`)
}
Note: This file needs to get imported in your top-most file, likely your src/index.ts via import './config' (placed before all other imports)
IProcessEnvAfter combining a few methods above, we can add some runtime checks for sanity to guarantee that our declared IProcessEnv interface reflects what ENV variables are set in our .env.* files. The contents below can also live in 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 { }
}
}
This will give us proper IntelliSense/tslint type checking, as well as some sanity when deploying to various environments.
Note that this also works for a ReactJS app (as opposed to a NodeJS server app). You can omit Step (2) because this is handled by create-react-app.
After executing with typescript latest version:
npm install -D --save @types/node
you can use process.env directly.
console.log(process.env["NODE_ENV"])
you will see the expected result if you have set NODE_ENV.
what worked for me is that everywhere I want to use process.env I first import dotenv and call config() on it. Also, remember to append ! at the end and ensure the attribute is defined in your .env file
import dotenv from 'dotenv';
dotenv.config();
export const YOUR_ATTRIBUTE = process.env.YOUR_ATTRIBUTE!;
process.env in only one place, perhaps a place that exports a configuration object built with process.env, etc? Less duplication of code, less to maintain.!. Rather define your types so they are correct.Here is a short function which is guaranteed to pull the process.env value as a string -- or to throw an error otherwise.
For something more powerful (but also bigger), others here have suggested 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;
}
You should then be able to write code like:
let currentEnvironment: string;
currentEnvironment = env('NODE_ENV');
I know this will help someone who searches for this and can't find the simple answer to why your proccess.env variables are making your compiler whine:
Install @types/node:
npm i @types/node
Then where ever you're including your env as a string, do this:
process.env.YOUR_ENV ?? ''
The double question marks allow you to check for null/undefined.
create a file like global.d.ts
declare global {
namespace NodeJS {
interface ProcessEnv {
SECRET: string;
}
}
}
export {};
export {}; was the key. Thanks!npm i @types/node"types": [ "node" ] to your tsconfig.json file in the compilerOptions section.I found that deliberately changing the path to the .env file was my issue as detailed here: https://stackoverflow.com/a/62288163/3605990
tl;dr
module:
import * as dotenv from "dotenv";
dotenv.config({ path: __dirname+'/.env' });
or commonjs:
require('dotenv').config({ path: __dirname+'/.env' });
Complementing previous responses and after some time with this problem, even installing @types/node, I found this answer. In short, just run a reload window:
"...Although, you probably have to restart typescript language server if it still uses previous version of the tsconfig. In order to do this in VS Code, you do Ctrl+Shift+P and Reload Window or TypeScript: Restart TS server if available..."
here's my solution with envalid (validating and accessing environment variables in 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
Important note: if you have a web app and you are using webpack.DefinePlugin to define process.env on your window, then these are they typings you are looking for:
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.
}
}
Just typecast the process.env.YOUR_VAR
Example:
mongoose
.connect(String(process.env.MONGO_URL), {
useNewUrlParser: true,
useFindAndModify: false
})
.then(() => console.log('DB connected'))
.catch((err: any) => console.error(err));
process is not declared.The best and easiest way to use node process.env in your typescript project is to first compile with tsc then run the compiled javascript file with node supplying your ENV var. Example (first make sure tsconfig.ts is what you want for the output directory also the name of compiled file, I am using dist as output directory and index.js as example):
cd my-typescriptproject
tsc
NODE_ENV=test node ./dist/index.js
For anyone coming here looking for an answer for Create React App projects specifically, your variable names should start with REACT_APP_
Read more here: https://facebook.github.io/create-react-app/docs/adding-custom-environment-variables
You could also use a type guard function. Something like this that has a return type of
parameterName is string
e.g.
function isEnvVarSpecified(envVar: string | undefined): envVar is string {
if(envVar === undefined || envVar === null) {
return false;
}
if(typeof envVar !== 'string'){
return false;
}
return true;
}
You can then call this as a type guard:
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
}
I wrote a module to simplify this. It has no dependencies so it's reasonably lightweight. It also works with dotenv, and you can pass a custom process.env to the env.from function if you need to.
It's mentioned in a few answers already, but here's an example:
Install it using yarn/npm:
npm install env-var --save
Then read variables:
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')
}
Or another:
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)
My way:
declare let process: Omit<NodeJS.Process, 'env'> & {
env: {
NODE_ENV: 'development' | 'production';
// Your variables goes here
};
};
ProcessEnvthat you're using? If it's the DefinitelyTyped definition that @Joe Clay shows, then the dotted notation should work (I can't reproduce your error in 2.4).