输入'字符串| undefined' 不能分配给类型 'string'。 “未定义”类型不能分配给“字符串”类型

时间:2021-06-01 02:24:37

标签: node.js typescript discord.js

我正在使用 TypeScript 声明以下变量:

const BOT_PREFIX: string = process.env.PREFIX;
const BOT_TOKEN: string = process.env.TOKEN;

我收到以下错误:

<块引用>

输入'字符串| undefined' 不能分配给类型 'string'。 类型 'undefined' 不能分配给类型 'string'.ts(2322)

我可以通过将数据类型更改为 any 来修复它,但我不想这样做。

1 个答案:

答案 0 :(得分:7)

节点的 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.PREFIXprocess.env.TOKEN 的假设不正确,您希望看到什么。


纯粹为了方便起见,您可能无法击败 non-null assertion operator (!)

const BOT_PREFIX: string = process.env.PREFIX!; // okay
const BOT_TOKEN: string = process.env.TOKEN!; // okay

在这里,您只是告诉编译器,即使它无法验证这一点,您也肯定会定义 process.env.PREFIXprocess.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 | undefinedundefined 的可能性已被 throw语句),因此您可以安全地将返回值分配给类型为 string 的变量。

这段代码显然不太方便,因为它需要额外的运行时代码,但现在,如果您的假设无效,您将在运行时立即获得一些反馈,而不是可能对编译器撒谎并具有奇怪的运行时行为。


Playground link to code