Home > Software engineering >  How to create a typescript type, for my context dispach based on the values of another interface?
How to create a typescript type, for my context dispach based on the values of another interface?

Time:12-19

I would like to create a type for my "reducer" function.

My function "reducer" receives 2 parameters, the first one is the current state, and the second one is what is sent in the context dispach (to use the reducer).

const reducer = (
    state: any,
    props: {
        action: string,
       value: any,
    } 
) => {
...
}

That second parameter will always be an object with 2 properties: action and value.

But, I don't like that the property "value" allows to enter whatever. That's why I like to create a dynamic "type".

I have an interface, with all the information that my context has.

DefaultValueContextInterface interface {
    floatMsgError: string;
    isOpenSidebar: boolean;
    .....
}

What I would like, is that this new "type" that I want to create only allows, for example:

{
    action: "floatMsgError",
    value: string,
} 

Why "value" only allows "string"? because in the interface "DefaultValueContextInterface" the property "floatMsgError" is of type string. And so with each one of the properties in the "DefaultValueContextInterface" interface but automatically. If the value of "action" sent to the function "reducer" was equal to "isOpenSidebar" then the value of "value" must be of type boolean.

I could create the type manually, simply:

{
    action: "floatMsgError",
    value: string,
} 
| {
    action: "isOpenSidebar",
    value: boolean,
}

But, I don't have those 2 properties in my cotext anything. There are a lot of them. And it would not be optimal to do it like that.

I also tried with "[P in keyof DefaultValueContextInterface]" but, I only manage to put it together as:

type Props = {
    [P in keyof DefaultValueContextInterface]: {
        action: P;
        value: DefaultValueContextInterface[P];
    };
};

Which doesn't work for me. Because it generates an object, which is not what I need. But the internal objects do come close to what I need. I just don't know how to make the loop another way to make it work.

Currently I have this:

type Props = {
  action: keyof DefaultValueContextInterface;
  value: DefaultValueContextInterface[keyof DefaultValueContextInterface];
};

But, this does not associate the value of "action" with the value of "value" at all :/

CodePudding user response:

Your mapped type approach is almost correct. You only need to create a union by indexing the type with keyof DefaultValueContextInterface.

interface DefaultValueContextInterface {
    floatMsgError: string
    isOpenSidebar: boolean
}

type Props = {
    [P in keyof DefaultValueContextInterface]: {
        action: P
        value: DefaultValueContextInterface[P]
    }
}[keyof DefaultValueContextInterface]

Playground

  • Related