3 votes

Déclarez de manière programmatique les types Typescript pour les clés de l'environnement dans mon env

Dire que j'ai ce fichier .env.local :

SOME_VAR="c'est très secret"
SOME_OTHER_VAR="ce n'est pas si secret, mais doit être différent pendant les tests"

y a-t-il un moyen de faire en sorte que typescript crée un type comme celui-ci de manière programmatique :

type TEnv = 'SOME_VAR' | 'SOME_OTHER_VAR'

Le cas d'utilisation que j'ai se présente comme ceci

export default function env(clé: TEnv): string {
  return process.env[clé] || Cypress.env(clé)
}

Je pense que je pourrais peut-être déclencher un script qui lit les clés via dotenv (ou bash) et qui écrit ensuite un fichier types.d.ts avec elles... Mais je voulais juste savoir s'il existe déjà un moyen en TS de faire cela ?

Mon dernier essai ressemble à ceci

import dotenv from 'dotenv'

class DynamicArray {
  ajouter(valeur: T): Array {
    let collection = new Array()
    collection.push(valeur)
    return collection
  }
}
const TEnvClé = new DynamicArray()

const fichierEnv = dotenv.config({ path: '.env.local' }).parsed
Object.keys(fichierEnv).forEach((clé) => TEnvClé.ajouter(clé))

export default function env(variable: TEnvClé): string {
  return process.env[variable] || Cypress.env(variable)
}

Mais cela ne fonctionne pas...

Note annexe

Le webpack utilisé par NextJS n'autorise pas process.env[clé] et Cypress lancera une erreur de référence. J'ai donc dû faire ceci :

export default function env(clé: TEnvClé): string {
  try {
    // doive essayer attraper à cause de l'erreur de référence Cypress
    return Cypress.env(clé)
  } catch {
    switch (clé) {
      case 'SOME_VAR':
        return process.env.SOME_VAR
      case 'SOME_OTHER_VAR':
        return process.env.SOME_OTHER_VAR
      default:
        return undefined
    }
  }
}

2voto

Norfeldt Points 1383

J'ai fait quelque chose qui fonctionne :)

envTypeWriter.mjs

import dotenv from 'dotenv'
import fs from 'fs'

const env = dotenv.config({ path: '.env.local' }).parsed
const typeText = `type TEnvKey =\n  | "${Object.keys(env).join('"\n  | "')}"`

fs.writeFileSync('env.d.ts', typeText)

package.json

"scripts": {
    ...
    "types": "node envTypeWriter.mjs"
  },

Ensuite, je fais simplement yarn types (et >Reload Window) dans vscode).

Je ne change pas mes variables si souvent donc c'est bien.

Version mise à jour

modèle :

utils/env.ts

export default function env(key: TEnvKey): string {
  try {
    // have to try catch because of Cypress reference error
    return Cypress.env(key);
  } catch {
    switch (key) {
      // START OF AUTO GENERATED CASES -- DO NOT REMOVE OR EDIT THIS COMMENT

// this part will be replaced

      // END OF AUTO GENERATED CASES -- DO NOT REMOVE OR EDIT THIS COMMENT
      default:
        return undefined;
    }
  }
}

// START OF AUTO GENERATED TYPES -- DO NOT REMOVE OR EDIT THIS COMMENT
// this will be replaced

envTypesWriter.ts

import { config } from 'dotenv'
import { writeFileSync, readFileSync } from 'fs'

const envLocal = config({ path: '.env.local' }).parsed // NOTE: Script has to be executed from the project root
const typeText = `type TEnvKey =\n  | "${Object.keys(envLocal).join('"\n  | "')}"`

const casesText = Object.keys(envLocal).reduce((acc, key) => {
  acc += `      case '${key}':\n`
  acc += `        return process.env.${key}\n`
  return acc
}, '')

const filePath = 'utils/env.ts'
let text = readFileSync(filePath, { encoding: 'utf8' })
console.log(`reading ${filePath}`)

if (!text) throw 'nothing read'

const casesStartLineMarker =
  '// START OF AUTO GENERATED CASES -- DO NOT REMOVE OR EDIT THIS COMMENT\n'
const casesEndLineMarker =
  '      // END OF AUTO GENERATED CASES -- DO NOT REMOVE OR EDIT THIS COMMENT\n'

text = `${
  text.split(casesStartLineMarker)[0]
}${casesStartLineMarker}${casesText}${casesEndLineMarker}${
  text.split(casesStartLineMarker)[1].split(casesEndLineMarker)[1]
}`

const typesLineMarker = '// START OF AUTO GENERATED TYPES -- DO NOT REMOVE OR EDIT THIS COMMENT\n'
const [untouchedCode, _types] = text.split(typesLineMarker)
const updatedText = `${untouchedCode}${typesLineMarker}${typeText}`

writeFileSync(filePath, updatedText, 'utf8')

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X