Awinograd
Awinograd

Reputation: 42

Why does enum value need to be coerced before object type is recognized properly?

I have an object that is discriminated on the type property which can be any value of a given enum. When I create a valid object and then pass it to a function, typescript complains that the types don't match. However, if I coerce the enum value then it's fine.

enum AorB {
  A = 'a',
  B = 'b',
};

type Bar_A = {
  type: AorB.A;
};

type Bar_B = {
  type: AorB.B;
}

type Bar = Bar_A | Bar_B;

function foo(a: Bar): void {}

const arg = {
  type: AorB.A,
};

// this would work but is extra writing
// const arg = {
//   type: AorB.A as AorB.A
// };

foo(arg); // Error
foo({
  type: AorB.A,
})

See the equivalent playground link

Upvotes: 0

Views: 131

Answers (1)

Titian Cernicova-Dragomir
Titian Cernicova-Dragomir

Reputation: 249716

Typescript will widen literal types unless it has a reason to keep them around so arg will be typed as {type: AorB } not { type: AorB.A, }.

If you explicitly use a type assertion AorB.A as AorB.A then typescript will preserve the literal type. If you assign the object literal to a location that requires Bar (such as the parameter to the function) typescript will again preserve the literal type.

Another option that will work is to type arg explicitly:

const arg: Bar = {
  type: AorB.A,
};

foo(arg);
foo({
  type: AorB.A,
})

Or use as const in 3.4 to get the compiler to keep literal types without having to specify the type again, although that will make the whole object readonly.

Upvotes: 2

Related Questions