9

I wish to restrict the assignable types of an object to a specific type. Example, an object where all keys must have number values, such as below:

interface NumberMap {
    [key: string]: number;
}

This works for enforcing the value restriction however I then won't be able to determine what keys actually exist inside the map variable.

const map: NumberMap = {
  one: 1,
  two: 2,
  three: 3,
};

// no error, but incorrect, this key does *not* exist
const lol = map.weoiroweiroew;

// Also cannot do this
type MyKeys = keyof map;

Is there a way to enforce an index signature without losing the information of what keys the object implementing that signature has?

3
  • I need the keys at compile time not run time Commented Jun 13, 2018 at 11:39
  • Your comment does not answer my question. There is no value restriction if I do that. Commented Jun 13, 2018 at 11:41
  • @JonasLochmann he wants to ensure that the type of the object literal extends the interface but get the actual type of the object literal too Commented Jun 13, 2018 at 11:43

2 Answers 2

7

The only way to do both restrict values, and preserve type information about what keys are actually in the implementing type is to use a generic helper function. The function will enforce that the object literal extends the interface, but it will infer the actual type of the object literal:

interface NumberMap {
    [key: string]: number;
}

function createNumberMap<T extends NumberMap>(v: T) {
    return v;
}
const map = createNumberMap({
    one: 1,
    two: 2,
    three: 3,
    // no: '' // error
});
map.one //ok
map.no //error
Sign up to request clarification or add additional context in comments.

2 Comments

Ah yes, forgot about that trick :) No way around using a helper function?
@EdwardSammutAlessi not as far as I know, at least no easy way. There is a way that requires you declare an extra type that will perform the validation, but I would not really recommend it
2

How about this ? I think this will restrict your objects keys to the given 3 indexes

type Index = 'one' | 'two' | 'three'
type NumberMap = { [k in Index]?: number }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.