Borislav Hadzhiev
Fri Feb 18 2022·3 min read
Photo by Carmen Marxuach
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 we know the shape of the values. The index signature specifies a key and
value of type string
.
// 👇️ function returning index signature // (a key-value structure with key and value strings) function getObj(): { [key: string]: string } { return { name: 'Tom', country: 'Chile' }; } // 👇️ Interface using index signature interface Person { [index: string]: string; } // 👇️ const p1: Person const p1: Person = { name: 'Tom', country: 'Chile' }; // 👇️ Type using index signature type Animal = { [index: string]: string; }; const a1: Animal = { name: 'Alfred', type: 'dog' };
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.
string
, it will return a string
.You might also see the index signature {[key: string]: any}
in examples. It
represents a key-value structure that when indexed with a string returns a value
of any
type (very broad).
Let's look at an example of how TypeScript warns us if we try to add a value of a different type than specified in our index signature.
interface Person { [index: string]: string; } // ⛔️ ERROR: Type 'number' is not assignable to type 'string'. const p1: Person = { name: 'Tom', age: 30 };
We've specified that when the object that has a type of Person
is indexed with
a string, it should return a string
.
Trying to set a key that is a string with a value of number
gets us an error.
You might try to override the type of a specific property with an index signature.
interface Person { [index: string]: string; // ⛔️ Error: Property 'age' of type 'number' is not // assignable to 'string' index type 'string'. age: number; }
But the type of the age
property in the example does not match the type of the
string index, so TypeScript gives us an error.
In this situation, you can set the type of the string index to a union.
interface Person { [index: string]: string | number; age: number; name: string; } // 👇️ const p1: Person const p1: Person = { name: 'Tom', country: 'Chile', age: 30 };
The type of the values with an index signature of type string
is a union of
string
and number
.
The age
and name
properties have a value that is a subtype of the union, so
we don't get an error.
Trying to add a property to the type that is not in the union, would cause an error.
interface Person { [index: string]: string | number; age: number; name: string; // ⛔️ ERROR: Property 'colors' of type 'string[]' is not assignable // to 'string' index type 'string | number'.ts(2411) colors: string[]; }
You can also set an index signature to readonly
if you need to prevent
assignment to their indices.
interface ReadonlyObj { readonly [index: string]: string; } const obj: ReadonlyObj = { name: 'Tom', country: 'Chile', }; // ⛔️ Index signature in type 'ReadonlyObj' // only permits reading. obj.name = 'Alfred';
We set the string index's type to readonly
, so the type checker gives us an
error if we try to write to a property that has a string key.