Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Typescript TS2322 error when using lookup types

Tags:

typescript

I'm racking my brain why the following code doesn't compile:

interface Circle { type: "circle"; }
interface Rectangle { type: "rectangle"; }
type Shape = Circle | Rectangle;

interface Circle { type: "circle"; }
interface Rectangle { type: "rectangle"; }
type ShapeTemplate = {
  type: Shape["type"];
};

const fromTemplate = (template: ShapeTemplate): Shape => template;

It breaks with:

TS2322: Type 'ShapeTemplate' is not assignable to type 'Shape'. Type 'ShapeTemplate' is not assignable to type 'Rectangle'. Types of property 'type' are incompatible. Type '"circle" | "rectangle"' is not assignable to type '"rectangle"'. Type '"circle"' is not assignable to type '"rectangle"'.

like image 985
Paweł Badeński Avatar asked Sep 19 '25 20:09

Paweł Badeński


1 Answers

The short answer is that it is generally too complex for the TypeScript compiler to reduce {x: A} | {x: B} to {x: A|B}.

You can read about this in the discussion at Microsoft/TypeScript#7553 and some other places I can't find right now. (Edit: also see Microsoft/TypeScript#18230.) I think the maintainers of the language don't consider it worthwhile to try to implement this, because most of the time it isn't useful in practice; types people really use generally have more than one property, and as soon as you have {x: A, y: P } | {x: B, y: Q}, a reduction to something like {x: A|B, y: P|Q} is not valid.

In practice, the workaround here is to just assert that a ShapeTemplate is assignable to Shape, like so:

const fromTemplate = (template: ShapeTemplate): Shape => template as Shape;

Hope that helps; good luck!

like image 63
jcalz Avatar answered Sep 22 '25 13:09

jcalz