Search code examples
typescriptindexingtype-safety

Why does Typescript not give an error when indexing into non-indexable types, and is there a way to make it do so?


While trying to use the map type, I have repeatedly shot myself in the foot by trying to get and set elements using square brackets. I realize that I need to be using map.get(key) and map.set(key,value) but after using Python and C# dictionaries for so long, I'm having a hard time getting this through my thick skull.

let m = new Map<string, string>();

// This doesn't generate any error, though it 
//  doesn't do what someone might assume it
//  would (doesn't add an element to the map)
m["foo"] = "bar"

// This doesn't generate an error either
m[1] = 2; 

// This does generate an error, even though
//  in javascript, m.foo means the same as 
//  m["foo"], so why does typescript treat
//  them differently?
m.foo = "bar"

// This is what someone really should be
//  doing to add an element to the map
m.set("baz", "qux")

The reason I use Typescript is usually because it prevents me from doing stupid things that the type does not support. However, in this case Typescript does not give an error. It doesn't seem to care that I'm trying to use square brackets to index into a map.

In fact, even for primitive data types like number it doesn't seem to mind me doing complete nonsense like this:

// Typescript allows you to index into any
//  type, even a number?!??!?!
let x = 3;
let y = 4;
x["crazy"] = "yes";

// But again the behaviour is inconsistent
// between indexing with [] versus .
// The following is an error in Typescript.
x.crazy = "no"

Or even my own class.

class MyClass {
    x: number;
}

let myInstance = new MyClass()
myInstance.x = 5;
myInstance["y"] = 10; // not an error

My questions are:

  1. What is the rationale for Typescript allowing indexing into any and all types?
  2. Considering that x.foo is synonymous with x["foo"] in javascript, why does Typescript treat them so differently?
  3. Is there a way I can turn on additional checks which will prevent indexing into types which are not intended to be indexable? Is there a way to mark a type as non-indexable so that you can't accidentally try to index into it?

Solution

  • With default compiler settings you can indeed index into objects you shouldn't index into. This was probably done to ease migration from JS to TS.

    You can enable the compiler checks regarding indexing (an other implicit uses of any) using the noImplicitAny flag, or more generally you can enable extra checks using the strict flag.