Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Typescript index signatures

Tags:

typescript

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?

like image 826
ed' Avatar asked Jun 13 '18 11:06

ed'


People also ask

What are index signatures in TypeScript?

Index signature is used to represent the type of object/dictionary when the values of the object are of consistent types. Syntax: { [key: KeyType] : ValueType } Assume that we have a theme object which allows us to configure the color properties that can be used across the application.

Is incompatible with index signature?

The error "Property is incompatible with index signature" occurs when a property is not compatible with the specified type of the index signature. To solve the error, change the type of the property or use a union to update the type in the index signature.

What is key string in TypeScript?

The {[key: string]: string} syntax is an index signature in TypeScript and is used when we don't know all the names of a type's properties ahead of time, but know the shape of the values. The index signature in the examples means that when an the object is indexed with a string , it will return a string .

Can TypeScript interface have methods?

A TypeScript Interface can include method declarations using arrow functions or normal functions, it can also include properties and return types. The methods can have parameters or remain parameterless.


2 Answers

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
like image 190
Titian Cernicova-Dragomir Avatar answered Nov 15 '22 22:11

Titian Cernicova-Dragomir


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 }
like image 35
Priyal Avatar answered Nov 15 '22 21:11

Priyal