Faz um tempinho que eu não escrevo aqui, mas hoje eu voltei. Voltei porque hoje configurei um servidor de node.js com typescript, e nele escrevi um sistema bem simples e util para fazer a verificação de tipagem das variaveis de ambiente, e é sobre ele que irei falar hoje.
O Código
Não vou ficar te enrolando com toda a história desse código, nem do projeto no qual estou trabalhando (isso é pra outro post). Se você só quiser o código, ele está logo abaixo. Se não entender algo ou só estiver curioso mesmo, fique à vontade para continuar lendo logo após o código.
import "dotenv/config";
import { z } from "zod";
const env = z.object({
PORT: z.coerce.number().max(65535).min(0),
NODE_ENV: z.enum(["development", "production"]),
});
export type Env = z.infer<typeof env>;
declare global {
namespace NodeJS {
export interface ProcessEnv {
[key: string]: any | undefined
}
interface ProcessEnv extends Env { }
}
}
env.parse(process.env);
Que bom que você chegou até aqui, pra começar, ultilizaremos duas bibliotecas: dotenv
e zod
. A primeira é para carregar as variaveis de ambiente do arquivo .env
para o process.env
, e a segunda é para fazer verificação de tipagem em qualquer objeto que você quiser. Os outros geralmente a usam para fazer verificação de tipagem em objetos que vem de uma API, mas eu a usei para fazer verificação de tipagem nas variaveis de ambiente.
Primeiro definimos o schema, que é o objeto que o zod usará para realizar a verificação de tipagem. Nele definimos todas as variaveis de ambiente que queremos verificar, e o tipo que elas devem ter. No meu caso, eu defini que a variavel PORT
deve ser um numero entre 0 e 65535, e que a variavel NODE_ENV
deve ser uma string que pode ser development
ou production
. Você pode definir qualquer tipo que quiser, desde que seja um tipo que o zod entenda.
const env = z.object({
PORT: z.coerce.number().max(65535).min(0),
NODE_ENV: z.enum(["development", "production"]),
});
Agora que vem a parada com o typescript, o zod oferece um ultilitario para convertermos um schema em um tipo do typescript, tipo esse que podemos usar para tipar qualquer objeto que queremos verificar. No meu caso, eu criei um tipo chamado Env
que é o tipo do meu schema env
.
export type Env = z.infer<typeof env>;
Lá vamos nós pra mais typescript, dessa vez um cadinho mais assustador, mas acredita em mim, é simples. o process.env
do node usa a interface ProcessEnv
para definir o tipo das variaveis de ambiente, e é nela que iremos injetar os tipos das variaveis de ambiente que temos. Mas tem um problema, a interface ProcessEnv
por definição aceita apenas string
e undefined
como tipos, e nosso campo PORT
sai como um tipo de number
. Para podermos injetar nossos tipos no ProcessEnv
precisamos redefini-lo para aceitar qualquer tipo de variavel, ou undefined
(any | undefined
).
declare global {
namespace NodeJS {
// Aqui redefinimos o tipo das variaveis de ambiente para aceitar qualquer tipo ou undefined
export interface ProcessEnv {
[key: string]: any | undefined
}
// Aqui injetamos nossos tipos
interface ProcessEnv extends Env { }
}
}
E por fim, a ultima parte do código, a parte que faz a verificação de tipagem. Aqui usamos o env.parse
para fazer a verificação de tipagem das variaveis de ambiente, e se alguma variavel não estiver de acordo com o schema definido, o zod irá lançar um erro que irá terminar o programa. E é isso, simples assim.
env.parse(process.env);
Essa ultima parte é bem customizavel também, você pode fazer o que quiser com o erro que o zod lança, você pode formatar a mensagem bonitinha, enviar uma notificação pra todos os seus engenheiros, ou simplesmente deixar o programa terminar. Eu escolhi a ultima opção, pois não tenho necessidade de fazer nada mais complexo por agora.
você pode aprender mais sobre o zod em zod.dev (sério, é uma biblioteca muito boa, vale a pena dar uma olhada)