Get keys of a Typescript interface as array of strings

ts-transformer-keys
typescript pick
typescript interface array
typescript interface constructor
typescript interface naming convention
typescript interface default value
typescript export interface
typescript record get keys

I've a lot of tables in Lovefield and their respective Interfaces for what columns they have. Example:

export interface IMyTable {
  id: number;
  title: string;
  createdAt: Date;
  isDeleted: boolean;
}

I'd like to have the property names of this interface in an array like this: const IMyTable = ["id", "title", "createdAt", "isDeleted"]; I cannot make an object/array based on the interface IMyTable directly which should do the trick because i'd be getting the interface names of the tables dynamically. Hence I need to iterate over these properties in the interface and get an array out of it. How do i achieve this result?

As of TypeScript 2.3 (or should I say 2.4, as in 2.3 this feature contains a bug which has been fixed in typescript@2.4-dev), you can create a custom transformer to achieve what you want to do.

Actually, I have already created such a custom transformer, which enables the following.

https://github.com/kimamula/ts-transformer-keys

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

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

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

Unfortunately, custom transformers are currently not so easy to use. You have to use them with the TypeScript transformation API instead of executing tsc command. There is an issue requesting a plugin support for custom transformers.

keyof to produce a runtime array · Issue #13267 · microsoft/TypeScript, E.g., interface Foo { prop1: number; prop2: string; } const x = keyof Foo; you would get from Object.keys since the TS types are not exact/final. I cannot make an object/array based on the interface IMyTable directly which should do the trick because i’d be getting the interface names of the tables dynamically. Hence i need to iterate over these properties in the interface and get an array out of it.

The following requires you to list the keys on your own, but at least TypeScript will enforce IUserProfile and IUserProfileKeys have the exact same keys (Required<T> was added in TypeScript 2.8):

export interface IUserProfile  {
  id: string;
  name: string;
};
type KeysEnum<T> = { [P in keyof Required<T>]: true };
const IUserProfileKeys: KeysEnum<IUserProfile> = {
  id: true,
  name: true,
};

keyof and Lookup Types in TypeScript, TypeScript 2.1 introduced the keyof operator and lookup types, which help With these two type annotations in place, obj must be an object and key must be a string. Let's assume we have defined the following Todo interface: to the Todo type to get back a type representing all its property keys, which  Fundamentally, when you do state[keys[i]], you're using a string to index into state.If your state object's type doesn't have an index signature, TypeScript won't let you do that (without a type assertion)

This should work

var IMyTable: Array<keyof IMyTable> = ["id", "title", "createdAt", "isDeleted"];

or

var IMyTable: (keyof IMyTable)[] = ["id", "title", "createdAt", "isDeleted"];

Handbook - Interfaces, interface LabeledValue { label : string; } function printLabel ( labeledObj : LabeledValue ) TypeScript comes with a ReadonlyArray<T> type that is the same as Object literals get special treatment and undergo excess property checking when  If I have a type type foo = Array<{ name: string; test: number; }>, would it be possible to get the type of the values within the array, in this case, the interface.I know there is keyof to get the keys, is there something similar for values?

Instead of defining IMyTable as in interface, try defining it as a class. In typescript you can use a class like an interface.

So for your example, define/generate your class like this:

export class IMyTable {
    constructor(
        public id = '',
        public title = '',
        public createdAt: Date = null,
        public isDeleted = false
    )
}

Use it as an interface:

export class SomeTable implements IMyTable {
    ...
}

Get keys:

const keys = Object.keys(new IMyTable());

Handbook - Advanced Types, In TypeScript, arrays are themselves a data type, just like number and string). And, regardless of which syntax you use for declaring an array, you'll find that the resulting interface IDictionary { [key: string]: Customer; };. TypeScript Version: 2.5.3 Would it be possible to have something like the keyof operator for arrays? The operator would be able to access the values in the array. Code With object we can do the following: const obj = {one: 1, two: 2} typ

I had a similar problem that I had a giant list of properties that I wanted to have both an interface, and an object out of it.

NOTE: I didn't want to write (type with keyboard) the properties twice! Just DRY.


One thing to note here is, interfaces are enforced types at compile-time, while objects are mostly run-time. (Source)

As @derek mentioned in another answer, the common denominator of interface and object can be a class that serves both a type and a value.

So, TL;DR, the following piece of code should satisfy the needs:

class MyTableClass {
    // list the propeties here, ONLY WRITTEN ONCE
    id = "";
    title = "";
    isDeleted = false;
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// This is the pure interface version, to be used/exported
interface IMyTable extends MyTableClass { };

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// Props type as an array, to be exported
type MyTablePropsArray = Array<keyof IMyTable>;

// Props array itself!
const propsArray: MyTablePropsArray =
    Object.keys(new MyTableClass()) as MyTablePropsArray;

console.log(propsArray); // prints out  ["id", "title", "isDeleted"]


// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// Example of creating a pure instance as an object
const tableInstance: MyTableClass = { // works properly!
    id: "3",
    title: "hi",
    isDeleted: false,
};

(Here is the above code in Typescript Playground to play more)

PS. If you don't want to assign initial values to the properties in the class, and stay with the type, you can do the constructor trick:

class MyTableClass {
    // list the propeties here, ONLY WRITTEN ONCE
    constructor(
        readonly id?: string,
        readonly title?: string,
        readonly isDeleted?: boolean,
    ) {}
}

console.log(Object.keys(new MyTableClass()));  // prints out  ["id", "title", "isDeleted"] 

Constructor Trick in TypeScript Playground.

Exploiting TypeScript Arrays -- Visual Studio Magazine, keyof T is the union of all string literals that can be used as a key for the record ( '​name' I can get a new array (of numbers I compare the outside number with):. Interfaces do not support mapped types (which is what you are looing for here). You can use a type alias, for most uses it should work the same (not all cases but if the types are known you can implement the type alias just as you would the interface).

Recursive keyof on interface : typescript, In Typescript, an interface can be used to describe an Object's required interface Person { name: string; age: number; } let p: Person = {name: "111-111​-111"}; let date: Date = new Date(); let ar: Array<number> = [1, 3, 5]; Object literals get special treatment and undergo excess property checking. keyof and Lookup Types in TypeScript January 6, 2017. JavaScript is a highly dynamic language. It can be tricky sometimes to capture the semantics of certain operations in a static type system. Take a simple prop function, for instance: function prop(obj, key) { return obj[key]; }

TypeScript - Using Interfaces to describe Object Properties, Omit type when extending an interface; Omitting specific properties when extending an interface TypeScript, like JavaScript, allows you to work with arrays of values. We can assign types to the object key-value pairs, like so: private constructor(public readonly name: string) {} /** * If get instance has not been initialized  Not exactly best answer to question but this trick new Array(someMap) saved me couple of times when I need both key and value to generate needed array. For example when there is need to create react components from Map object based on both key and value values.

typescript-cheatsheet, To get properties values using Object.values(); To get properties enumerableKeys array contains natureColors own properties keys: 'colorC' and use as key any object type (plain object uses as key a string primitive type). How to use TypeScript and typing; Software design and good coding practices. Is key-value pair available in Typescript? Yes. Called an index signature: interface Foo { [key: string]: Bar; } let foo:Foo = {}; Here keys are string and values are Bar. More. You can use an es6 Map for proper dictionaries, polyfilled by core-js.

Comments
  • Thanks for your response, i already saw and installed this custom transformer yesterday but since this uses typescript 2.4, this of no use to me as of now.
  • Hi, this library serves exactly my requirement too, however, I am getting ts_transformer_keys_1.keys is not a function when i follow the exact steps in the documentation. is there a workaround this?
  • Neat! Do you think it can be extended to take a dynamic type parameter (note 2 in the readme)?
  • @HasithaShan look closely into docs - you have to use TypeScript compiler API in order package to work
  • Dang. The linked github issue is pretty rough. If you have a github account, I recommend piling on the thumbs ups. It's the only way something like this will achieve a simpler solution.
  • Not that it's wrong, but to be clear here you are just "enforcing the values of the array" to be correct. The developer still needs to write them down twice, manually.
  • While what Aidin said might be true, for some cases, this was exactly what I was looking for, for my case. Thank you.
  • This won't prevent key duplicates or missing keys. Like var IMyTable: Array<keyof IMyTable> = ["id", "createdAt", "id"];
  • For me it was also what I was looking for because I want to optionally accept the keys but nothing more than the keys defined in the interface. Didn't expect this to be default with the above code. I guess we would still need a common TS way for that. Thanks in any case for the above code!
  • The propsArray is only accessible when you initialized the keys though.
  • I don't get what you mean by "initialized" @denkquer. In the first example, propsArray is available before the tableInstance if that's what you mean, so clearly before the initialization of the instance. However, if you are referring to the fake values assigned in MyTableClass, those are just there to shortly imply the "type" of the properties. If you don't want them, you can go with the constructor trick in the PS example.
  • In my understanding a value is initialized when it has any value. Your "constructor trick" is misleading because you can't just replace the MyTableClass with the latter one and expect to receive keys in the propsArray as uninitialized vars and types are stripped at runtime. You always have to supply them with some kind of default value. I've found that initializing them with undefined is the best approach.