Home > Enterprise >  Typescript template literal for object key mapping
Typescript template literal for object key mapping

Time:05-26

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

Playground

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]

Playground

  • Related