You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Describe the bug:
Types generated for properties using environment variables are incorrect. Environment variable configs should use string | undefined as that's what @types/node uses for environment variables. However, during interface generation, each environment variable is either string or undefined, depending on whether or not it's defined at the time. When it is, the property will have a type of string. Otherwise, it will have a type of undefined.
Suspected Cause
Type generation follows the following process:
Load configs for the appropriate environment (based on values for relevant environment variables)
Merge them together
Resolve values for config properties using environment variables
Pass the resulting object to json-to-ts
e.g.
// config/default.json{"foo": "bar"}
// config/env/dev.json{"foo": "@@FOO"}
When process.env.FOO is undefined, mergeAllConfigs results in the final object:
{"foo": undefined}
json-to-ts, seeing undefined, resolves the type for that particular config to undefined.
Possible Solutions
Solution 1: use null instead of undefined (worse solution)
it("should work with multiple key words and optional fields",function(){constjson={"hello world": null};constexpected=`interface RootObject { 'hello world'?: any;}`;constactual=JsonToTS(json).pop();assert.strictEqual(expected.trim(),actual.trim());});
This is better than undefined as this typing is correct, but it's not very specific.
Solution 2: use optional property name syntax
json-to-ts has undocumented behavior for creating optional types based on property names. Its implemented in this function. Properties ending in --? will have optional types, and the --? suffix gets removed from the resulting type. e.g.
{
"foo--?": "foo"
}
Turns into
interfaceRootObject{foo?: string}
We could use this to our advantage. During type generation, we could insert dummy values into values that use environment variables and add the --? suffix to the key. This would result in the correct type. The downside is that this solution relies on undocumented behavior.
Steps To Reproduce:
Create a bare-bones default config
// config/default.json{"foo": "@@FOO"}
Do not set a value for FOO in your terminal. Then, run the CLI. The following type declaration will be created:
I would like to propose something completely different here —
We should create types first and then have readers that read data from various sources (files, env etc.) and merge them together to create a value of the expected type.
import{config,Source}from'node-config-ts'typeColor="RED"|"BLUE"|"GREEN"typeConfig={port: number,color: Color}// Generates a config with some default valuesconstauto: Source<Config>=config.automatic.as<Config>()// Reads from default.jsonconstdefault: Source<Config>=config.file("./default.json").as<Config>()// Reads from production.jsonconstproduction: Source<Config>=config.file("./production.json").as<Config>()// Read from env variablesconstenv: Source<Config>=config.env.as<Config>()// Merge all the configurationsconstmerged: Source<Config>=auto.orElse(default).orElse(production).orElse(env)console.log(awaitmerged.generate())// Will print the final config
Describe the bug:
Types generated for properties using environment variables are incorrect. Environment variable configs should use
string | undefined
as that's what@types/node
uses for environment variables. However, during interface generation, each environment variable is eitherstring
orundefined
, depending on whether or not it's defined at the time. When it is, the property will have a type ofstring
. Otherwise, it will have a type ofundefined
.Suspected Cause
Type generation follows the following process:
json-to-ts
e.g.
When
process.env.FOO
is undefined,mergeAllConfigs
results in the final object:json-to-ts
, seeingundefined
, resolves the type for that particular config toundefined
.Possible Solutions
Solution 1: use
null
instead ofundefined
(worse solution)json-to-ts
handlesnull
values, but notundefined
values, by making their types optional andany
. The below test from their codebase demonstrates this behavior.This is better than
undefined
as this typing is correct, but it's not very specific.Solution 2: use optional property name syntax
json-to-ts
has undocumented behavior for creating optional types based on property names. Its implemented in this function. Properties ending in--?
will have optional types, and the--?
suffix gets removed from the resulting type. e.g.Turns into
We could use this to our advantage. During type generation, we could insert dummy values into values that use environment variables and add the
--?
suffix to the key. This would result in the correct type. The downside is that this solution relies on undocumented behavior.Steps To Reproduce:
Create a bare-bones default config
Do not set a value for
FOO
in your terminal. Then, run the CLI. The following type declaration will be created:Next, set foo and run the CLI again.
export FOO=foo node ./bin/cli
The following type declaration will be created:
Expected behavior:
The type declaration below should be generated:
Typescript Version:
Tested on
3.7.5
and4.9.4
. Should not affect the behavior.node-config-ts version:
3.1.0
and3.2.0
The text was updated successfully, but these errors were encountered: