在TS的项目开发中,经常会出现process.env
无法自动补齐的情况。
console.log(process.env.MY_ENV_VARIABLE); // 不会自动补齐
而且会被推断成string或者undefined。
如果你要把它作为string传给一个函数,那你就必须做一下类型转换。哪怕你知道它一定会存在,都必须这样子做。不然会报错。
那如何解决呢?
方案1:增强全局类型
你可以增强全局类型NodeJS.ProcessEnv,以包含你的环境变量:
// globals.d.ts
namespace NodeJS {
interface ProcessEnv {
MY_ENV_VARIABLE: string;
}
}
这依赖于全局接口NodeJS.ProcessEnv上的声明合并,添加一个额外的属性MY_ENV_VARIABLE。
现在,在项目中的每个文件中,你将获得MY_ENV_VARIABLE的自动完成,它将以字符串的形式键入。
然而,这并不能保证环境变量确实存在于你的系统中。也许它真的不存在。
方案2:封装获取方法
为了确保程序在启动时不会因为缺少关键环境变量而崩溃,可以对必需的变量进行校验。例如,可以编写一个专门的配置模块,读取并验证所有需要的环境变量。
const getEnv = (key: keyof NodeJS.ProcessEnv, defaultValue?: string): string => {
const value = process.env[key];
if (!value && !defaultValue) {
throw new Error(`Environment variable ${key} is missing`);
}
return value || defaultValue!;
};
export const config = {
apiUrl: getEnv('API_URL'),
port: getEnv('PORT', '3000'),
databaseUrl: getEnv('DATABASE_URL'),
};
这种方法主要是通过通用的条件判断消除undefined的情况,不仅提供了环境变量的类型安全性,还能在项目启动时进行严格的环境变量校验。
方案3:使用t3-env在运行时验证它
如果你想验证所有环境变量在运行时都存在,你可以使用t3-env等库。
t3-env 是 T3 Stack 中的一个用于管理和验证环境变量的库。它的主要目的是在 TypeScript 项目中增强环境变量的类型安全和一致性。
t3-env 的核心目标是确保在项目中使用的环境变量具备以下特性:
- 类型安全:通过类型定义确保环境变量的类型正确,避免开发过程中出现类型错误。
- 运行时验证:在项目启动时对环境变量进行验证,确保必需的变量已经定义且格式正确。
- 环境隔离:确保开发、生产等环境使用的环境变量不会混淆或出现错误配置。
t3-env 基于 Zod 库,它提供了 schema 定义功能,可以对环境变量进行严格的类型验证。这里有一个例子:
import { createEnv } from "@t3-oss/env-core";
import { z } from "zod";
export const env = createEnv({
server: {
DATABASE_URL: z.string().url(),
OPEN_AI_API_KEY: z.string().min(1),
},
clientPrefix: "PUBLIC_",
client: {
PUBLIC_CLERK_PUBLISHABLE_KEY: z.string().min(1),
},
runtimeEnv: process.env,
});
如果任何环境变量缺失或与模式不匹配,这将在运行时失败。Zod 会抛出详细的错误报告,显示哪个环境变量不匹配以及出现了什么问题。
Zod拥有强大的验证功能。
- 字符串验证:z.string() 用于指定一个环境变量必须是字符串类型。
- URL 验证:z.string().url() 确保一个字符串是合法的 URL。
- 枚举类型:z.enum() 可以限制一个环境变量的值必须在一组选定的值之内。
- 正则表达式匹配:z.string().regex() 用于对字符串进行正则验证,如验证 PORT 变量是否为数字。
- 可选字段:z.string().optional() 表示这个变量是可选的。
也可以根据自己的需求自定义环境变量的验证规则,例如你需要确保 API_TIMEOUT 是一个数字,并且在 1 到 10 之间,你可以这样定义:
export const customSchema = z.object({
API_TIMEOUT: z.string().transform(Number).refine(val => val >= 1 && val <= 10, {
message: "API_TIMEOUT must be between 1 and 10",
}),
});
在这个示例中,API_TIMEOUT 被转换成 Number 类型,并且通过 refine() 方法确保它的值在 1 到 10 之间。
它还为你的环境变量提供了单一的真实来源-env。这意味着你可以在整个代码库中使用env,你将获得环境变量的自动完成和类型检查。
哪种方案更好?
如果你的项目很小,并且你不想添加额外的依赖项,则增强全局类型是一个很好的解决方案。
但是,如果你担心运行时缺少环境变量,t3-env是一个不错的选择。
本文由mdnice多平台发布
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。