dennis
dennis

Reputation: 610

Strange union type behavior in TypeScript

Could anyone explain the following behavior in TypeScript (2.4.1)?

Scenario: I have a button which could be "red" or "red and round" (modifications). I would like to have the following syntax to describe it:

button.mods = "red";
button.mods = ["red", "round"];
button.mods = { red: true, round: false };

To describe all of this, I use the following interfaces:

interface HasMods<T extends string>{ 
    mods: T | T[] | { [key in T]?: boolean } 
}

interface Button extends HasMods<"round" | "red"> { 
}

Ok, now we can do some testing:

let b: Button;
b.mods = "red"; //ok, correct 
b.mods = "green"; //error, correct

b.mods = ["red"]; //ok, correct
b.mods = ["green"]; //error, correct

b.mods = {red: true}; //ok, correct
b.mods = {red: true, green: true}; //error, correct

So far everything is perfect. But now a mystery:

b.mods = {red: true, map: false}; //ok, why ???

Why is the value "map" valid for my object of type { [key in T]?: boolean } where T is "red" | "round"? "map" is neither "red" or "round".

Actually, all array methods are valid here - "every", "copyWithin", etc...

Upvotes: 0

Views: 92

Answers (1)

eusoj
eusoj

Reputation: 374

If you take a look in the proto definition of the array, "map" is one of the attributes.

So when you're comparing "map in T" it's true, because it's being compared inside an array structure, if it were an object it will be false

console.log("map" in {"element":4}) // false
console.log("map" in [4]) //true

Upvotes: 2

Related Questions