Environment variables arrive as strings, then scripts convert them into typed config.

environment config A typed config object keeps string environment input at the edge of a script.

Environment Config Record

debugText
env.ts
Replay: real traced execution (multi-file project)
type EnvConfig = {
    debug: boolean;
    retries: number;
};

function readConfig(env: Record<string, string>): EnvConfig {
    return {
        debug: env.DEBUG === "true",
        retries: Number(env.RETRIES)
    };
}

const debugText: string = "false";
const env: Record<string, string> = {
    DEBUG: debugText,
    RETRIES: "3"
};
const config: EnvConfig = readConfig(env);

console.log(`${config.debug ? "debug" : "normal"}:${config.retries}`);
type EnvConfig = {
    debug: boolean;
    retries: number;
};

function readConfig(env: Record<string, string>): EnvConfig {
    return {
        debug: env.DEBUG === "true",
        retries: Number(env.RETRIES)
    };
}

const debugText: string = "true";
const env: Record<string, string> = {
    DEBUG: debugText,
    RETRIES: "3"
};
const config: EnvConfig = readConfig(env);

console.log(`${config.debug ? "debug" : "normal"}:${config.retries}`);
  1. debugText ← false, env ← [object Object]

    10    };11}1213const debugText→ false: string = "false";  //@debugText="true"14const env→ [object Object]: Record<string, string> = {15    DEBUG: debugTextfalse,16    RETRIES: "3"17};18const config: EnvConfig = readConfig(env[object Object]);
  2. function readConfig(env: Record<string, string>): EnvConfig

    3    retries: number;4};56function readConfig(env[object Object]: Record<string, string>): EnvConfig {7    return {8        debug: env.DEBUG === "true",9        retries: Number(env.RETRIES3)10    };11}
  3. config ← [object Object]

    16    RETRIES: "3"17};18const config→ [object Object]: EnvConfig = readConfig(env[object Object]);1920console.log(`${config.debugfalse ? "debug" : "normal"}:${config.retries3}`);
    outputnormal:3
  1. debugText ← true, env ← [object Object]

    10    };11}1213const debugText→ true: string = "true";14const env→ [object Object]: Record<string, string> = {15    DEBUG: debugTexttrue,16    RETRIES: "3"17};18const config: EnvConfig = readConfig(env[object Object]);
  2. function readConfig(env: Record<string, string>): EnvConfig

    3    retries: number;4};56function readConfig(env[object Object]: Record<string, string>): EnvConfig {7    return {8        debug: env.DEBUG === "true",9        retries: Number(env.RETRIES3)10    };11}
  3. config ← [object Object]

    16    RETRIES: "3"17};18const config→ [object Object]: EnvConfig = readConfig(env[object Object]);1920console.log(`${config.debugtrue ? "debug" : "normal"}:${config.retries3}`);
    outputdebug:3

Follow the Config

  1. debugText starts as the string "false".
  2. env.DEBUG stores that string, and env.RETRIES stores "3".
  3. readConfig(env) converts DEBUG into a boolean.
  4. It also converts RETRIES into the number 3.
  5. The typed config prints normal:3. | raw env strings | parsed config | printed output | | --- | --- | --- | | DEBUG=false, RETRIES=3 | debug=false, retries=3 | normal:3 | | DEBUG=true, RETRIES=3 | debug=true, retries=3 | debug:3 |

Exercise: env.ts

Reproduce normal:3, then set debugText to the pinned value true and predict debug:3.