1

I have an object type which I want to map to a strongly typed key, value array.

This is what I came up with so far:

export interface StepWidgetItem<T, V> {
    key: T;
    value: V;
}

interface UseStepWidgetsContainer<T extends object> {
    data: T;
}

interface UseStepWidgetsContainerProps<T extends object> {
    items: StepWidgetItem<keyof T, T[keyof T]>[];
}

export const useStepWidgetsContainer = <T extends object>({
    items,
}: UseStepWidgetsContainerProps<T>): UseStepWidgetsContainer<T> => {
    const data = {} as T;

    console.log(items);

    return {
        data,
    };
};

The problem i when I call it like this:

interface Data {
    test: string;
    test2: number;
}

useStepWidgetsContainer<Data>({
    items: [
        {
            key: 'test',
            value: 'test',
        },
        {
            key: 'test2',
            value: 'test', // should be an error, but string is currently allowed...
        },
        {
            key: 'test2',
            value: 1,
        },
    ],
});

The value of array item with key: 'test2' must be a number, but currently it may be any type of the values of Data, so string|number.

Is it possible to force a number when key === 'test2'?

1 Answer 1

2

You are very close The problem is that StepWidgetItem<keyof T, T[keyof T]> will mix any key of T with any value in T.

The solution is to first associate the key with the value creating a type for each property, for ex: StepWidgetItem<"test", string> StepWidgetItem<"test2", number>. We can do this using a mapped type to first create for each property, the associated StepWidgetItem and then index into the mapped type using [keyof T] to get a union of all StepWidgetItem types we just created.

interface UseStepWidgetsContainerProps<T extends object> {
    items: Array<{
      [P in keyof T]: StepWidgetItem<P, T[P]>
    }[keyof T]>
}

Playground Link

Sign up to request clarification or add additional context in comments.

1 Comment

This method has a problem, a complicated-looking type error appears when I use it in my case, Similar to what you'll see if you open the Playground Link

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.