Iterate over interface properties in TypeScript

I need to map interface properties to objects:

interface Activity {
  id: string,
  title: string,
  body: string,
  json: Object
}

I currently do:

headers: Array<Object> = [
  { text: 'id', value: 'id' },
  { text: 'title', value: 'title' },
  { text: 'body', value: 'body' },
  { text: 'json', value: 'json' }
]

This gets very repetitive. What I would like is something like this:

headers: Array<Object> = Activity.keys.map(key => {
  return { text: key, value: key }
})

Solution 1:

You can't, interfaces are only for compile time because javascript doesn't support it.

What you can do is something like:

const Activity = {
    id: "",
    title: "",
    body: "",
    json: {}
}

type Activity = typeof Activity;
const headers: Array<Object> = Object.keys(Activity).map(key => {
    return { text: key, value: key }
});

(code in playground)

Solution 2:

If you are okay with having it added during a compile time and you are using TypeScript >= 2.4.1, you can try the way proposed here.

Basically, you should add the ts-transformer-keys dependency, custom transformer, like a basic one and you'll be able to list the properties like this:

import { keys } from 'ts-transformer-keys';

interface Props {
    id: string;
    name: string;
    age: number;
}
const keysOfProps = keys<Props>();

console.log(keysOfProps); // ['id', 'name', 'age']

Solution 3:

if you would like to keep the interface ability you can do the following, @Nitzan Tomer is right. Interfaces are part of the type system, hence they are only relevant in compile time as they are omitted in the transpiled code.

class Activity {
    public id: string = '';
    public title: string = '';
    public body: string = '' ;
    public json: Object = {};
}

let activity = new Activity()

const headers: Array<Object> = Object.keys(Activity).map(key => {
    return { text: key, value: key }
});

console.log(JSON.stringify(headers))

Solution 4:

This approach might be a bit overkill, but i use it since i need JSON schemas anyway for validating the back end's response structure. Getting the keys from interfaces is just a nice side-effect of converting typescript interfaces into json schemas:

Using a typescript to json schema converter, one could get interfaces keys along with their types. The resulting json objects are large and verbose, so a parsing helper function could come in handy to recursively constructing simpler JS objects the way you want out of them. The good news is that a json schema always has the same structure, so it's easy to navigate.