Reputation: 1327
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
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
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
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
Reputation: 1243
try this
const object1 = {
a: 'somestring',
b: 42,
c: false
};
console.log(Object.keys(object1));
output: Array ["a", "b", "c"]
Upvotes: -1