0

Let's say I have a type that maps to a database table where the keys are the column names:

interface MyTable {
  foo: string;
  bar: number;
}

And then I have another type that maps from a form field to the table row.

interface MyTableMap<T> {
  columnName: keyof T;
  formFieldName: string;
  value: any;
}

// I want this to generate an error because 12345 is not a string based on the column name of "foo".
const first: MyTableMap<MyTable> = { columnName: "foo", value: 12345 };

In the example above I don't want to define value: any but rather have it be the type that it is supposed to be based on the value of columnName. I can't seem to figure out how to do this without passing a second generic. We know the key is "foo" so how can I tell TypeScript what the correct type for value should be?

themanatuf
  • 2,880
  • 2
  • 25
  • 39
  • I see where this is going, you should have a look at this [this post](https://stackoverflow.com/questions/73387637/construct-typescript-type-from-array-of-objects/73389365#73389365) if you plan to do optional typings – nook Aug 22 '22 at 14:05

1 Answers1

2

You can generate a union of all field-value pairs. So for your example we should generate: { columnName: 'foo', value: string } | { columnName: 'bar', value: number }

We can do this using a mapped type to generate the type for each field and then get the desired union indexing back into the mapped type:

type MyTableMap<T> = {
    [P in keyof T]:{
        columnName: P;
        value: T[P];
    }
}[keyof T]

// Error
const bad: MyTableMap<MyTable> = { columnName: "foo", value: 12345 };
const ok: MyTableMap<MyTable> = { columnName: "foo", value: "12345" };

Playground Link

Titian Cernicova-Dragomir
  • 230,986
  • 31
  • 415
  • 357