I defined my generic type as
interface IDictionary<TValue> { [key: string|number]: TValue; }
But TSLint's complaining. How am I supposed to define an object index type that can have either as key? I tried these as well but no luck.
interface IDictionary<TKey, TValue> { [key: TKey]: TValue; } interface IDictionary<TKey extends string|number, TValue> { [key: TKey]: TValue; } type IndexKey = string | number; interface IDictionary<TValue> { [key: IndexKey]: TValue; } interface IDictionary<TKey extends IndexKey, TValue> { [key: TKey]: TValue; }
None of the above work.
Use the keyof typeof syntax to create a type from an object's keys, e.g. type Keys = keyof typeof person . The keyof typeof syntax returns a type that represents all of the object's keys as strings.
The indexing type is itself a type, so we can use unions, keyof , or other types entirely: type I1 = Person ["age" | "name"]; type I1 = string | number. type I2 = Person [keyof Person ]; type I2 = string | number | boolean.
Use the typeof operator to get the type of an object or variable in JavaScript. The typeof operator also returns the object type created with the "new" keyword. As you can see in the above example, the typeof operator returns different types for a literal string and a string object.
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 .
You can achieve that just by using a IDictionary<TValue> { [key: string]: TValue }
since numeric values will be automatically converted to string.
Here is an example of usage:
interface IDictionary<TValue> { [id: string]: TValue; } class Test { private dictionary: IDictionary<string>; constructor() { this.dictionary = {} this.dictionary[9] = "numeric-index"; this.dictionary["10"] = "string-index" console.log(this.dictionary["9"], this.dictionary[10]); } } // result => "numeric-index string-index"
As you can see string and numeric indices are interchangeable.
In javascript the keys of object can only be strings (and in es6
symbols as well).
If you pass a number it gets converted into a string:
let o = {}; o[3] = "three"; console.log(Object.keys(o)); // ["3"]
As you can see, you always get { [key: string]: TValue; }
.
Typescript lets you define a map like so with number
s as keys:
type Dict = { [key: number]: string };
And the compiler will check that when assigning values you always pass a number as a key, but in runtime the keys in the object will be strings.
So you can either have { [key: number]: string }
or { [key: string]: string }
but not a union of string | number
because of the following:
let d = {} as IDictionary<string>; d[3] = "1st three"; d["3"] = "2nd three";
You might expect d
to have two different entries here, but in fact there's just one.
What you can do, is use a Map
:
let m = new Map<number|string, string>(); m.set(3, "1st three"); m.set("3", "2nd three");
Here you will have two different entries.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With