Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Is it possible to access the instanced value of an object property in a TypeScript interface

Consider the following type for a column within a data table:

interface Column<T> {
  key: keyof T;
  title: string;
  format?: (value: T[keyof T], record: T) => string | number;
}

T is the data type of the table records, and the value to be displayed in the column is indexed by the key property. A format function would perform custom formatting or other processing for a specific column to be shown in the table, and so accepts the value of the column, which is T[keyof T], and the record itself.

The issue this presents is that T[keyof T] represents a union type of all data types contained within in type T.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

If, for example, T were a Person with the type:

interface Person {
  name: string;
  weight: number;
  birthday: Date;
}

then T[keyof T] would equal string | number | Date. But, when an object is instantiated with a format function, the specific type of the value cannot be determined.

const column: Column<Person> = {
  key: 'birthday',
  title: "Birth Date",
  render: (value) => value.getFullYear();
}

This would throw an error because TypeScript cannot be certain that value is in fact of type Date and so contains the getFullYear() method.

I know that it’s possible to add a second generic argument to the type, like so:

export interface Column<T, K extends keyof T> {
  key: K;
  title: string;
  format?: (value: T[K], record: T) => string | number;
}

In this case, it is possible to type the previous example correctly by specifying the key name:

const column: Column<Person, 'birthday'> = {
  key: 'birthday',
  title: "Birth Date",
  format: (value) => value.getFullYear()
}

But this is not practically useful, as almost all usages of a Column would exist in an Array with a single type declaration.

Is it somehow possible to access the specific instanced value of the key property in an interface/type, or create an auxiliary type that does so, such that you can define a property which is the type of the specific property indexed by that exact key?

I know I can simply resolve these errors with type assertions, but it bothers me that I can’t find a cleaner way to do it.

>Solution :

This approach uses a ‘throwaway’ Mapped type to create a union of all valid Column structures, but where each one is key-specific. You can hover over value in the Typescript Playground to prove it…

interface Person {
  name: string;
  weight: number;
  birthday: Date;
}

type Column<T> = {
  [K in keyof T]: {
    key: K;
    title: string;
    format?: (value: T[K], record: T) => string | number;
  };
}[keyof T];

const column: Column<Person> = {
  key: "birthday",
  title: "The day you were born",
  format: (value, record) => "some formatted string",
};
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading