I have a system config (provided by me) that describes what a user config (provided by the user) is capable of.
Then I want to pass each piece of the user config and evaluate it according to the system setup.
To show what I mean, here is some sample code. It should output 2 lines:
const systemConfig = {
a: (arg: number) => arg,
b: (arg: string) => arg,
}
type InferConfig<T extends {}> = { [K in keyof T]: T[K] extends (arg: infer U) => any ? U : never }
const userConfig: InferConfig<typeof systemConfig> = {
a: 123,
b: 'whateva',
};
// (everything above working as expected)
for (const key in userConfig) {
if (key in systemConfig) {
console.log(systemConfig[key](userConfig[key])); // correct output but highlights errors
console.log(systemConfig[key as keyof typeof systemConfig](userConfig[key as keyof typeof userConfig])); // luckily doesn't work because I want to avoid "as" if possible
}
}
Playground
Another requirement is that the loop (not working section of the code) must not include logic in the form of "if (key === 'a') ..." (i.e. depend of a
)
You code does not contain the index signature for the type of Object: systemConfig
. Which means any attempt of using string
to index systemConfig
will be prevented. For example we can define the Object with an index signature this way:
const systemConfig: {[key: string]: (arg: any) => string | number} = {
a: (arg: number) => arg,
b: (arg: string) => arg,
}
In the above code, [key: string]
means string
keys can be used to assign values to properties of systemConfig
. And (arg: any) => string | number
means the value should be a function that takes an argument of any
type and returns either string
or number
(you can modify this)
Once done, you can remove this extra line of code and check it (playground):
console.log(systemConfig[key as keyof typeof systemConfig](userConfig[key as keyof typeof userConfig]));
For your reference: What does a TypeScript index signature actually mean?
Usually we first define the config type and then extend the transformer.
But if you do want it, see below code.
Playground
type ConfigTransformer = {
[K in string]: (arg: any) => any
}
type ConfigInput<T extends ConfigTransformer> = {
[K in keyof T]: T[K] extends (arg: infer U) => any ? U : never
}
type ConfigOutput<T extends ConfigTransformer> = {
[K in keyof T]: T[K] extends (arg: any) => infer U ? U : never
}
const systemConfig = {
a: (arg: number) => arg,
b: (arg: string) => arg,
}
type SystemInput = ConfigInput<typeof systemConfig>
type SystemOutput = ConfigOutput<typeof systemConfig>
const userConfig: SystemInput = {
a: 123,
b: 'whateva',
};
function transform<T extends ConfigTransformer>(transformer: T, input: ConfigInput<T>){
// you must do this `as` because typescript not infer the correct key type
const keys = Object.keys(transformer) as (keyof T)[];
for(const key of keys){
console.log(transformer[key](input[key]))
}
}
transform(systemConfig, userConfig);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With