Simon
Simon

Reputation: 3016

Use keys of an object as union-type

I've got a object (let it be frozen so typescript may handle its keys better):

const obj = Object.freeze({
    'hello': 64,
    'world': 20
}) as {[key: string]: number};

Now I have a function where the user can pick values by their keys:

const pick = (keys: Array<string>): Array<number> => {
    const values = [];

    for (const key of keys) {

        // Check if object contains property-key
        if (!(key in obj)) {
            throw new Error(`There's no such key: ${key}`);
        }

        values.push(obj[key]);
    }

    return values;
};

That's looking good so far and works flawlessly during runtime where I check if the user passed any invalid keys. But how can I tell TS that only keys from obj can be used?

I could do Array<'hello' | 'world'> but I'd need to update it any time I add new properties to obj which is kinda annoying.

Related questions but they all seem to use types whereas I only have a object (which can be frozen if that helps):

  1. Make union type of objects from type keys (He got a type, I'm with a object)
  2. get union type of object keys filtered by type of object value (Basically the same as 1. but he wants the type whereas I'm trying to build a type out of my object)
  3. Get keys of union of objects in TypeScript (Looks good but he also got a type...)

Upvotes: 6

Views: 7671

Answers (1)

Maciej Sikora
Maciej Sikora

Reputation: 20162

const obj = Object.freeze({
    'hello': 64,
    'world': 20
});

const pick = (keys: Array<keyof typeof obj>) {...}

As you can see I have removed as {[key: string]: number}; as it was widening the type, where you wanted to have it strict.

Next things is Array<keyof typeof obj> I declare here that I accept as argument only array of keys from type of obj.

Array<keyof typeof obj> evaluates dynamically into ("hello" | "world")[], fortunately as you wanted it will reflect every change in original obj

Upvotes: 13

Related Questions