I've just started using io-ts instead of runtypes in a new project. The pattern I have for config validation is to create an object with the types of each part of the config;
const configTypeMap = {
jwtSecret: t.string,
environment: t.string,
postgres: postgresConnectionType
} as const
type Config = { [Key in keyof typeof configTypeMap]: t.TypeOf<typeof configTypeMap[Key]> }
and another object with the values that should satisfy that type;
const envVarMap = {
jwtSecret: process.env.JWT_SECRET,
environment: process.env.ENVIRONMENT,
postgres: {
user: process.env.POSTGRES_USER,
password: process.env.POSTGRES_PASSWORD,
host: process.env.POSTGRES_HOST,
port: process.env.POSTGRES_PORT,
database: process.env.POSTGRES_DATABASE,
}
} as const
Then I create a function that takes in a key and returns a validated piece of the config under that key;
const getConfig = <T extends keyof Config>(key: T): Config[T] => {
const result: Either<t.Errors, Config[T]> = configTypeMap[key].decode(envVarMap[key])
if (isLeft(result)) {
throw new Error(`Missing config: ${key}`)
}
return result.right
}
This worked fine in runtypes (although it looked a little different). However, in io-ts, configTypeMap[key].decode
is inferred as;
Left<t.Errors> | Right<string> | Right<{
user: string;
password: string;
host: string;
port: string;
database: string;
}>
which has lost all context about which key the decode function was accessed from. I can cast result
back to the correct type of Either<t.errors, Config[T]>
, but I would like a way to do this without casting to validate that I'm not just ignoring an error.
EDIT:
playing around in the playground, I've managed to get a reproducing example that does not involve io-ts, so I think this is just a problem with my understanding of typescript inference. I'd still like to find a way to end up with a function that has the signature <T extends keyof Config>(key: T): Config[T]
.
By removing the
Config
type and setting the return type of theget
function toStatic<typeof config[T]>
, the desired response can be obtained. I don't know if you need theConfig
type for something else, or if this will work withio-ts
but that may fix your problem.Here's an updated playground with an example.