Search code examples
javascripttypescripttypespartialkeyof

Typescript - Restrict values of object keys to some possible values, but don't make them mandatory


I've got some types defined as:

export const ABC= {
  A: 'A',
  B: 'B',
  C: 'C',
} as const;

export const DEF = {
  D: 'D',
  E: 'E',
  F: 'F',
} as const;

export type AbcTypes = (typeof ABC)[keyof typeof ABC];
export type DefTypes = (typeof DEF)[keyof typeof DEF];

Now, I'd like to create an object that can have only values present in those types as keys, but it doesn't need to have them all, so I'm writing the following:

type MyNewDictionary = {
  [pKey in AbcTypes]: {
    [eKey in DefTypes]: {
      onClick: () => void;
      onCancel: () => void;
    }
  }
};
...
const dictionary: MyNewDictionary = {
  [ABC.A]: {
    [DEF.D]: {
      onClick: () => null,
      onCancel: () => null,
    }
  }
};

However, whenever I try to set some of these object keys, it complains because the rest are missing:

Type: { D: { onClick: () => void; onCancel: () => void; } } is missing the following properties from type: ...

I've tried using Partial and using keyof, with the same results.

Here you can see a working Typescript playground.

How could I write this so that I can only use keys inside those defined types, but without the obligation to have all the keys used?


Solution

  • Probably mapping modifiers is the thing you're looking for.

    In your playground, just add two question marks as below:

    type MyNewDictionary = {
      [pKey in AbcTypes]?: {
        [eKey in DefTypes]?: {
          onClick: () => void;
          onCancel: () => void;
        }
      }
    };