Alphi Henry
Alphi Henry

Reputation: 1

TypeScript: How to define a type with nested objects

I'm trying to define this object type.

colors: {
  text: "#343D48", // body color and primary color
  text_secondary: "#02073E", // secondary body color
  heading: "#565F67", // primary heading color
  heading_secondary: "#0F2137", // heading color
  background: "#FFFFFF", // body background color
  background_secondary: "#F9FBFD", // secondary background color
  border_color: "#E5ECF4", // border color
  primary: "#78F0AC", // primary button and link color
  secondary: "#29CC5F", // secondary color - can be used for hover states
  muted: "#7B8188", // muted color
  dark: "#343D48",
  accent: "#609", // a contrast color for emphasizing UI
  yellow: "#F6C416",
  error: "#F65241",

  // highlight  a background color for highlighting text
  modes: {
    dark: {
      text: "#fff",
      background: "#000",
      primary: "#0cf",
      secondary: "#09c",
      muted: "#111",
    },
  },
},

This is what I wrote so far, I'm not sure how to define nested objects with TypeScript. How do I define the type for the code above? This is what I have so far:

export type Color = {
[colorName: string]: string;
};

Upvotes: 0

Views: 4086

Answers (1)

Viraj Shah
Viraj Shah

Reputation: 790

In your current type definition, you have the following:

export type Color = {
    [colorName: string]: string;
};

The above code is the same as saying:

export type Color = Record<string, string>

Instead, you should clearly define each field in the type definition. Defining a Record specifies the key-type and value-type for the object but does not specify the name of each key or the type of each value (in case some keys have another data type).

In this case, you are looking for an interface:

export interface ColorDefinition {
  text: string;
  text_secondary: string;
  heading: string;
  heading_secondary: string;
  background: string;
  background_secondary: string;
  border_color: string;
  primary: string;
  secondary: string;
  muted: string;
  dark: string;
  accent: string;
  yellow: string;
  error: string;
  modes: {
    dark: {
      text: string;
      background: string;
      primary: string;
      secondary: string;
      muted: string;
    };
  };
}

export type { ColorDefinition };

The same way you can also use type to define an interface:

type ColorDefinition = {
    primary: string;
    ...
}

export type { ColorDefinition };

If you would like to write this interface (since you have repeating key-value pairs) correctly, I would write your type definition as such:

interface SimpleColorDefinition {
    text: string;
    background: string;
    primary: string;
    secondary: string;
    muted: string;
}

interface UIColorDefinition extends SimpleColorDefinition {
    text_secondary: string;
    heading: string;
    heading_secondary: string;
    background_secondary: string;
    border_color: string;
    dark: string;
    accent: string;
    yellow: string;
    error: string;
    modes: {
        dark: SimpleColorDefinition;
    };
}

If you want the modes key to be an object with any value for key names, then you can do this instead:

modes: Record<string, SimpleColorDefinition>

Upvotes: 2

Related Questions