I'm trying to create a generic type that would map the keys using template literals. In general i just want all the keys listed in the generic type to be present in the output type, but modified slightly. Something along the lines of:
type TFoobar = "foo" | "bar";
const foobar: TFlagDict<TFoobar> = {
"foo_flag": true,
"bar_flag": true
};
I have tried implementing it like so:
type TFlagDict<TProperties extends string> = {
[key in TProperties]: {[k in `${key}_flag`]: boolean}
}[TProperties]
And while it does have a proper typing, it makes the properties optional (at least one is required, but there is nothing that enforces they are all present)
const foo: TFlagDict<TFoobar> = {
"foo_flag": true
}; //valid, shouldnt be
const bar: TFlagDict<TFoobar> = {
"bar_flag": true
}; //valid, shouldnt be
const foobar: TFlagDict<TFoobar> = {
"foo_flag": true,
"bar_flag": true
}; //valid
CodePudding user response:
You were close:
type TFoobar = "foo" | "bar";
const foobar: TFlagDict<TFoobar> = {
"foo_flag": true,
"bar_flag": true
};
type TFlagDict<TProperties extends string> = {
[key in TProperties as `${key}_flag`]: boolean // key remapping
}
type O = TFlagDict<TFoobar>
const foo: TFlagDict<TFoobar> = {
"foo_flag": true
}; //error
const bar: TFlagDict<TFoobar> = {
"bar_flag": true
}; //error
const foobar2: TFlagDict<TFoobar> = {
"foo_flag": true,
"bar_flag": true
}; //valid
You are allowed to use as
inside iterator. See docs for more context
CodePudding user response:
You can use TFooBar
instead of key
to enforce such validation:
type TFlagDict<TProperties extends string> = {
[key in TProperties]: {[k in `${TFoobar}_flag`]: boolean}
}[TProperties]