Home > Software design >  How to type nested object in object literal
How to type nested object in object literal

Time:10-19

I've got a tailwind.config.ts. I'd like to add type DMSans-Regular as a ValidFont. How can I achieve this?

type ValidFont = "DMSans-Regular"

module.exports = {
  theme: {
    extend: {
      fontSize: {
        md: "32px",
      },
      fontFamily: {
        primary: "DMSans-Regular"
      }
    },
  },
};

CodePudding user response:

The easiest way to do this would be to use the satisfies operator which will be released with TypeScript 4.9. This lets you contextually interpret the fontFamily property as a Record<string, ValidFont>, meaning an object with any keys but whose properties are a ValidFont, without actually widening the property to that type and forgetting about the actual keys and values:

type ValidFont = "DMSans-Regular" | "Velveetica"

const exp = {
  theme: {
    extend: {
      fontSize: {
        md: "32px",
      },
      fontFamily: {
        primary: "DMSans-Regular",
        secondary: "DMSans-Spicy", // error
        tertiary: "Velveetica"
      } satisfies Record<string, ValidFont>
    },
  },
};

If you need to do this before TypeScript 4.9 you can simulate the satisfies operator with a curried function like this:

const satisfiez = <T,>() => <U extends T>(u: U) => u

const exp = {
  theme: {
    extend: {
      fontSize: {
        md: "32px",
      },
      fontFamily: satisfiez<Record<string, ValidFont>>()({
        primary: "DMSans-Regular",
        secondary: "DMSans-Spicy", // error
        tertiary: "Velveetica"
      })
    },
  },
};

Playground link to code

  • Related