Indexable types allow you to define types where properties are accessed via an index. This can be particularly useful for arrays, dictionaries, or any structure where elements are accessed by keys (indices).
You can define indexable types using the bracket syntax for indices (either number
or string
) to specify the type of the key, and the type of the corresponding value.
Example 1: Indexable Array Type
interface StringArray {
[index: number]: string; // index of type number, value of type string
}
let myArray: StringArray;
myArray = ["Bob", "Fred"];
let myStr: string = myArray[0]; // OK: myStr is a string
StringArray
is an indexable type where the index is anumber
, and the value at that index is astring
.- You can access elements like
myArray[0]
, and they will be of typestring
.
Example 2: Class with Indexable Types
class Animal {
name: string;
}
class Dog extends Animal {
breed: string;
}
// Error: indexing with a numeric string might get you a completely separate type of Animal!
interface NotOkay {
[x: number]: Animal; // The index is a number, but value can be an Animal
[x: string]: Dog; // The index is a string, but value is a Dog
}
- This causes a conflict because index signatures with different types (i.e.,
number
andstring
) are incompatible if they return different types (Animal
andDog
).
Example 3: Number Dictionary
interface NumberDictionary {
[index: string]: number; // Index type is a string, value type is a number
length: number; // length property is valid
name: string; // Error: `name` is not a valid property of the dictionary
}
NumberDictionary
is an indexable type where you can index it with a string and get a number.- The
name
property, however, is not compatible because it doesn’t fit the index signature of the dictionary.
Example 4: Mixed Type Dictionary
interface NumberOrStringDictionary {
[index: string]: number | string; // Values can be either a number or a string
length: number; // OK: length is a number
name: string; // OK: name is a string
}
NumberOrStringDictionary
allows bothnumber
andstring
values for the index, and also defines some specific properties (length
andname
).
Example 5: Readonly Indexable Types
interface ReadonlyStringArray {
readonly [index: number]: string; // Readonly array of strings
}
let myArray: ReadonlyStringArray = ["Alice", "Bob"];
myArray[2] = "Mallory"; // Error: Cannot assign to '2' because it is a read-only property
ReadonlyStringArray
is an indexable type where the elements are readonly.- Trying to modify any element of this array (
myArray[2] = "Mallory"
) results in an error.
Key Points:
- Index signatures allow an object to be indexed by a type (e.g.,
string
ornumber
). - You can specify what the values of those indexed properties should be (e.g.,
string
ornumber
). - Readonly indexable types make the elements of an array or object immutable, i.e., you cannot modify the elements after they are set.
- Conflicts can arise if you define conflicting index signatures for different types (like
number
andstring
).