Home > Back-end >  Unexpected behaviour with intersection types in Typescript
Unexpected behaviour with intersection types in Typescript

Time:10-08

I've tried to break out the simplest test case I can of a real-world problem I have. I'm trying to build out some useful type objects, but I'm being stymied by an error I don't really understand. In the below, palette3 and palette4 type-check, but I'm having to be much more explicit than I'd like, and I'd like palette2 to type-check. Are there any simple tweaks I can make that will make palette2 work?

enum Color {
  Red,
  White,
  Blue,
  Green,
  Black,
}

interface Attr {
  foo: unknown;
  bar: unknown;
  baz: unknown;
};

type WhichColors = Attr & Record<string, Color >;
const palette1 : WhichColors = { foo: Color.Blue, bar: Color.Green, baz: Color.Black };

type Monochrome = WhichColors & Record<string, Color.White | Color.Black>;

// Doesn't type-check
const palette2: Monochrome = {
  foo: Color.Black,
  bar: Color.White,
  baz: Color.Black
};

// Typechecks but clunky
const palette3: Monochrome = {
  foo: Color.Black as Color.White | Color.Black,
  bar: Color.White as Color.White | Color.Black,
  baz: Color.Black as Color.White | Color.Black,
};

// Also typechecks but also clunky
const palette4 = {
  foo: Color.Black,
  bar: Color.White,
  baz: Color.Black,
} as Monochrome;

CodePudding user response:

You should be using keyof Attr instead of string to remove the need for the intersection:

type WhichColors = Record<keyof Attr, Color>;

Playground (renamed Attr to Attributes because it conflicts with Attr from the DOM API)


Your original solution did not work, because the intersection actually resolves to this:

type WhichColors = {
    [x: string]: Color;
    foo: unknown;
    bar: unknown;
    baz: unknown;
};

which you can see if you use this "trick" to simplify the type:

type WhichColors = (Attributes & Record<string, Color>) extends infer O ? ({ [K in keyof O]: O[K] }) : never;
  • Related