3

I am making a Black Jack app in pure TypeScript, but I get an error when creating the cards inside of a deck.
So far I have 2 classes and 2 enums to work with.

export enum Color {
  Hearts = 0,
  Spades,
  Diamonds,
  Clubs,
  Count,
  Hidden,
}

export enum Value {
  Two = 0,
  Three,
  Four,
  Five,
  Six,
  Seven,
  Eight,
  Nine,
  Ten,
  Knight,
  Queen,
  King,
  Ace,
  Count,
  Hidden,
}

export class Card {
  private color: Color;
  private value: Value;
  private isHidden: Boolean;

  constructor(color: Color, value: Value) {
    this.color = color;
    this.value = value;
    this.isHidden = true;
  }
}

import { Card, Color, Value } from './Card';

export default class Deck {
  private cards: Array<Card> = [];

  public Deck = (): void => {
    for (let colorIx = 0; colorIx < Color.Count; colorIx++) {
      for (let valueIx = 0; valueIx < Value.Count; valueIx++) {
        let c = new Card(Color[colorIx], Value[valueIx]);
        this.AddCard(c);
      }
    }
  };

  public AddCard = (card: Card): void => {
    this.cards.push(card);
  };
}

This part here is where things go wrong.

let c = new Card(Color[colorIx], Value[valueIx]);

It, gives me an error saying:

Argument of type 'string' is not assignable to parameter of type 'Color'.

But the weird thing is that the Value enum does not give me an error at all, and as far as I can see they are pretty much the same in their construction. Anyone knows what is going on?
Why is one enum accepted (Value) in the constructor while the other (Color) isnt?

Sub-Zero
  • 63
  • 4

1 Answers1

2

TypeScript enums are slightly unintuitive; it may be helpful to check out what your code compiles to to see why it's throwing the error that it is.

Taking Color for example: TS compiles Color to an object that's roughly equivalent to:

const Color = {
  [0]: "Hearts",
  [1]: "Spades",
  [2]: "Diamonds",
  // ...
  Hearts: 0,
  Spades: 1,
  Diamonds: 2,
  // ...
}

so when you do Color[0], you're actually getting the literal string "Hearts", which isn't what you want. To convert from a number to the corresponding numeric enum, you actually just need to typecast with as:

for (let colorIx = 0; colorIx < Color.Count; colorIx++) {
  for (let valueIx = 0; valueIx < Value.Count; valueIx++) {
    let c = new Card(colorIx as Color, valueIx as Value);
    this.AddCard(c);
  }
}

Under the hood, Color.Hearts is compiled to just 0, so it's fine to cast 0 as Color.

If you'd like to read more, here are a couple SO threads with further discussion.

superhawk610
  • 2,457
  • 2
  • 18
  • 27