I'm trying to create a type based on a design token JSON file.
The JSON object has the following format:
{
"Black": {
"4": { "value": "#f6f6f6" },
"6": { "value": "#f2f2f2" },
"10": { "value": "#e8e8e8" },
"20": { "value": "#d3d3d3" },
"30": { "value": "#bcbcbc" },
"40": { "value": "#a7a7a7" },
"50": { "value": "#909090" },
"60": { "value": "#7b7b7b" },
"70": { "value": "#646464" },
"80": { "value": "#4e4e4e" },
"90": { "value": "#383838" },
"100": { "value": "#222222" }
},
"Blue": {
"4": { "value": "#F5F8F8" },
"8": { "value": "#EBF0F1" },
"10": { "value": "#E5EBED" },
"20": { "value": "#CCD9DC" },
"30": { "value": "#B2C5CA" },
"40": { "value": "#99B3B9" },
"50": { "value": "#7F9FA7" },
"60": { "value": "#668C96" },
"70": { "value": "#4C7984" },
"80": { "value": "#336673" },
"100": { "value": "#004050" }
},
"Teal": {
"20": { "value": "#ccfbf0" },
"40": { "value": "#99f8e1" },
"60": { "value": "#66f4d3" },
"80": { "value": "#33f1c4" },
"100": { "value": "#00edb5" }
}
}
I've create a union type for the colours using type Color = keyof typeof colorJSON;
I now want to create another union type for all the nested keys inside the colour objects that are the tint levels e.g. type Tint = '4' | '6' | '8' etc...
but can't work out how to recursively iterate through colours and refer to the keys inside.
---Edit---
I want the type to automatically update if the JSON file gets more colours added to it so it must iterate through the structure rather than directly referencing the colour names
CodePudding user response:
Consider this example:
const colorJSON = {
"Black": {
"4": { "value": "#f6f6f6" },
"6": { "value": "#f2f2f2" },
"10": { "value": "#e8e8e8" },
"20": { "value": "#d3d3d3" },
"30": { "value": "#bcbcbc" },
"40": { "value": "#a7a7a7" },
"50": { "value": "#909090" },
"60": { "value": "#7b7b7b" },
"70": { "value": "#646464" },
"80": { "value": "#4e4e4e" },
"90": { "value": "#383838" },
"100": { "value": "#222222" }
},
"Blue": {
"4": { "value": "#F5F8F8" },
"8": { "value": "#EBF0F1" },
"10": { "value": "#E5EBED" },
"20": { "value": "#CCD9DC" },
"30": { "value": "#B2C5CA" },
"40": { "value": "#99B3B9" },
"50": { "value": "#7F9FA7" },
"60": { "value": "#668C96" },
"70": { "value": "#4C7984" },
"80": { "value": "#336673" },
"100": { "value": "#004050" }
},
"Teal": {
"20": { "value": "#ccfbf0" },
"40": { "value": "#99f8e1" },
"60": { "value": "#66f4d3" },
"80": { "value": "#33f1c4" },
"100": { "value": "#00edb5" }
}
}
type Colors = typeof colorJSON
type Values<T> = T[keyof T]
type ColorMap<T extends Record<string, Record<string, unknown>>> = {
[Prop in keyof T]: keyof T[Prop]
}
type Result = Values<ColorMap<Colors>>
ColorMap
- iterates through json keys (Black/Blue/Teal) and obtains union of keys of nested obj.
Values
- returns the union of all object values.
Since Object values are unions of keyof json nested objects, compisition of ColorMap
and Values
gives you the union of all keys of nested objects.
P.S. I don't think you need to recursively iterate through this object type. However, if you are interested in recursive solutions you can check my article
CodePudding user response:
You can use bracket notation to navigate to the nested object's type and use keyof
, and alternate between the different colors:
type ColorJSON = typeof colorJSON;
type Color = keyof ColorJSON;
type Tint = keyof ColorJSON['Black'] | keyof ColorJSON['Blue'] | keyof ColorJSON['Teal']
For this particular data, you could leave out Teal since its keys are contained in Blue already.