I have a variable that is an object of arrays:
cssColorsObject = {
red: ["lightsalmon", "salmon", "darksalmon", "lightcoral", "indianred", "crimson", "firebrick", "red", "darkred"],
orange: ["coral", "tomato", "orangered", "gold", "orange", "darkorange"],
yellow: [...
}
I would like to create a type/interface for future object variables that contain some of the keys (eg "red", "orange", "yellow"), and some or all of that key color's properties, eg:
{
red: ["lightsalmon", "salmon"], // OK
orange: [], //OK
yellow: ["lightsalmon"], // NOT OK - because light salmon is a color associated with the "red" key in the original object
}
I have worked out the following:
type CssColorKeys = keyof typeof cssColorsObject; // = "red" | "orange" | "yellow" | "green" , etc
type CssColorValues = typeof cssColorsObject[CssColorKeys][number]; // = "lightsalmon" | "salmon"... | "maroon"
type NewRecord = Record<CssColorKeys, CssColorValues> // Not what I want as this requires all properties and the exact same array.
I imagine I need to use partials, but I'm struggling to implement them here.
Full credit to @captain-yossarian for answer below. I just wanted to add a simplified solution, based on his answer:
type CssColorsPartial = Partial<{
[Prop in keyof typeof cssColorsObject]: Array<typeof cssColorsObject[Prop][number]>;
}>;
I've created another type
for a mapped type with mandatory keys and optional array values here
First of all, you need to make cssColorsObject
immutable.
const cssColorsObject = {
red: ["lightsalmon", "salmon", "darksalmon", "lightcoral", "indianred", "crimson", "firebrick", "red", "darkred"],
orange: ["coral", "tomato", "orangered", "gold", "orange", "darkorange"],
yellow: ['lemon']
} as const
Then iterate through cssColorsObject
keys and create the desired type.
type PartialCSS<T extends Record<string, ReadonlyArray<string>>> =
Partial<{
[Prop in keyof T]: Array<T[Prop][number]>
}>
I have used have unpacked T[Prop]
array into new similar Array<T[Prop][number]>
because T[Prop]
is immutable tuple where order of elements is preserved whereas new type does not require exact element order. Drawback, it allows you to use two similar elements.
Whole code:
const cssColorsObject = {
red: ["lightsalmon", "salmon", "darksalmon", "lightcoral", "indianred", "crimson", "firebrick", "red", "darkred"],
orange: ["coral", "tomato", "orangered", "gold", "orange", "darkorange"],
yellow: ['lemon']
} as const
type PartialCSS<T extends Record<string, ReadonlyArray<string>>> =
Partial<{
[Prop in keyof T]: Array<T[Prop][number]>
}>
const result: PartialCSS<typeof cssColorsObject> = {
red: ['salmon'],
yellow:['salmon'] // expected error
}