Chris Drackett
Chris Drackett

Reputation: 1327

How to convert type object keys into an array of strings type in typescript

given the following input in typescript:

type InputObjectType = {
  a: string
  b: number
  c: {}
}

how can I get the following type:

type ObjectKeysArrayType = ['a', 'b', 'c']

so far I can only get as far as:

type AllPossibleKeys = (keyof InputObjectType)[]

which gives me ["a" | "b" | "c"] which is close, but not what I'm looking for in this case.

I need an array that always contains all the key strings in the given type object. The only way I know to enforce this, for example when a user adds a new key to the object that the key is also added to the array is via something like this.

Upvotes: 14

Views: 17600

Answers (4)

Krzysztof Madejski
Krzysztof Madejski

Reputation: 8027

I use two approaches:

// Option 0: Define type using object
const someTypeExample = {
  a: 1,
  b: 'str',
  c: 'foo' as 'foo'|'bar'
};

type SomeType0 = typeof someTypeExample;


// Option 1: If object stores different types
type SomeType = {
  a: number;
  b: string;
}

const typeVar: SomeType = {
    a: 10,
    b: 'string'
}

// used for typechecking
type SomeTypeKey = keyof SomeType;

// create an array to be used in runtime
// disadvantage is that properties need to be repeated
const keys: SomeTypeKey[] = ['a', 'b']; // type checked
// TODO what I'm missing is:
// const keys = keys<SomeTypeKey>(); that would return ['a', 'b'] during transpiling
// ie. native support of https://github.com/kimamula/ts-transformer-keys 
// which is out of scope for TS: https://github.com/microsoft/TypeScript/issues/13267
let isValidKey = keys.includes('c' as SomeTypeKey)


// Option 2: start from keys array definition, in case all values have the same type

const myKeys = ['foo', 'bar'] as const; // as const does the magic
type MyKey = typeof myKeys[number]; // = 'foo' | 'bar'

type MyMap = Record<MyKey, string>;
type MyMap2 = { [key in MyKey]: string };

Upvotes: 0

George
George

Reputation: 163

Not sure if you're still looking for a solution here, but hopefully this helps.

If what you want is a type that requires that the variable be an array of strings only containing values equal to the keys of your object, then what you have listed should work.

type InputObjectType = {
  a: string
  b: number
  c: {}
}

type AllPossibleKeys = (keyof InputObjectType)[]

AllPossibleKeys will be a type equal to ("a"|"b"|"c")[]. This looks to be what you've asked for, but there is a caveat with how I'm guessing you want to use this.

const fieldArray1: AllPossibleKeys = ['a', 'b', 'c']; //valid
const fieldArray2: AllPossibleKeys = ['a', 'b', 'c', 'd']; //will throw a Typescript error
const fieldArray3: AllPossibleKeys = ['a', 'b']; //this is also valid though as each member is a valid value

If you instead want an array of all the keys in a type, there's not a way to do this explicitly that I'm aware of. However, if you are able to use an interface instead of a type, then you can do the following:

import { keys } from 'lodash';

interface InputObject = {
  a: string
  b: number
  c: {}
}

class InputObjectStub implements InputObject {
  a = null;
  b = null;
  c = null;
}

const fieldArray1 = keys(new InputObjectStub()); //returns ['a', 'b', 'c']

Note though, that this won't enforce optional attributes. If you need to do that, change your class definition to class InputObjectStub implements Required<InputObject> {...

Edit: spelling

Upvotes: 6

julianobrasil
julianobrasil

Reputation: 9377

That's not currently possible because the type information is not available during runtime. You can try your code on Typescript Playground. When you do that, you'll find out that this code:

type InputObjectType = {
  a: string
  b: number
  c: {}
}

is transpiled to nothing. It simply doesn't exist after the code is transpiled to javascript. As it doesn't exist during runtime, no runtime action is possible, like iterate through its properties, or even print them out.

Upvotes: 0

chirag sorathiya
chirag sorathiya

Reputation: 1243

try this

const object1 = {
  a: 'somestring',
  b: 42,
  c: false
};

console.log(Object.keys(object1));

output: Array ["a", "b", "c"]

Upvotes: -1

Related Questions