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;