节点的process.env 具有以下类型定义(来自this declaration file,它使用定义为here 的类型):
interface ProcessEnv {
[key: string]: string | undefined
}
因此,就 TypeScript 的编译器而言,您在 process.env 下访问的任何属性都将是 string | undefined 类型。那是union,这意味着process.env.RANDOMKEY(例如)要么是string,要么是undefined。一般来说,这是正确的类型;编译器不知道实际设置了哪些环境变量。
所以这是一个问题:
const BOT_PREFIX: string = process.env.PREFIX // error!
并且编译器会警告您process.env.PREFIX 可能是undefined,因此将其视为string 是不安全的。
处理这个问题的方法取决于您是想要方便还是类型安全,以及如果您对 process.env.PREFIX 和 process.env.TOKEN 的假设不正确,您希望看到什么。
纯粹为了方便,你可能无法击败non-null assertion operator (!):
const BOT_PREFIX: string = process.env.PREFIX!; // okay
const BOT_TOKEN: string = process.env.TOKEN!; // okay
在这里,您只是告诉编译器,即使它无法验证这一点,您也可以确定 process.env.PREFIX 和 process.env.TOKEN 将被定义。这实际上只是抑制了编译器警告;它在运行时仍然与您的原始代码做同样的事情。这意味着如果您的断言被证明是错误的,那么您可能会在运行时遇到编译器无法帮助您解决的问题:
BOT_PREFIX.toUpperCase(); // runtime error if BOT_PREFIX is undefined after all
所以要小心。
另一方面,您可以尝试通过处理未设置您期望的环境变量的情况来使代码更安全。例如:
function getEnvVar(v: string): string {
const ret = process.env[v];
if (ret === undefined) {
throw new Error("process.env." + v + " is undefined!");
}
return ret;
}
const BOT_PREFIX: string = getEnvVar("PREFIX");
const BOT_TOKEN: string = getEnvVar("TOKEN");
这里我们编写了一个名为getEnvVar() 的函数,它获取环境变量的名称并返回其值,只要该值是string。如果未定义环境变量,则会引发运行时错误。 TypeScript 通过control flow analysis 了解getEnvVar() 的返回类型是string(而不是string | undefined;undefined 的可能性已被throw 语句消除),因此您可以安全地分配返回值到string 类型的变量。
此代码显然不太方便,因为它需要额外的运行时代码,但现在与其可能对编译器撒谎并产生奇怪的运行时行为,如果您的假设无效,您将在运行时立即获得一些反馈。
Playground link to code