Home > front end >  How to type several property keys based on Enum?
How to type several property keys based on Enum?

Time:07-06

I want to create some interface to be used as a type for objects that have two properties and the names of those properties are based on an enum. You can see my solution below, but I think it's not flexible.

enum DiapasonBorders {
  MinInclude = 'minInclude',
  MinExclude = 'minExclude',
  MaxInclude = 'maxInclude',
  MaxExclude = 'maxExclude'
}

interface CaseA {
  [DiapasonBorders.MinInclude]: number;
  [DiapasonBorders.MaxInclude]: number;
}

interface CaseB {
  [DiapasonBorders.MinInclude]: number;
  [DiapasonBorders.MaxExclude]: number;
}

interface CaseC {
  [DiapasonBorders.MinExclude]: number;
  [DiapasonBorders.MaxInclude]: number;
}

interface CaseD {
  [DiapasonBorders.MinExclude]: number;
  [DiapasonBorders.MaxExclude]: number;
}

export type DiapasonBordersSetting = CaseA | CaseB | CaseC | CaseD;

so now I can create object when can be only one property with "min" and only one with "max" e.g

const obj: DiapasonBordersSetting = {
  minInclude: 4,
  maxExclude: 56
}

const obj2: DiapasonBordersSetting = {
  minExclude: 4,
  maxExclude: 56
}

Does anybody have some ideas how to improve this code? Something like:

type MinExcludeOrInclude = DiapasonBorders.MinInclude | DiapasonBorders.MinExclude;
type MaxExcludeOrInclude = DiapasonBorders.MaxInclude | DiapasonBorders.MaxExclude;

type DiapasonBordersSetting = {
  [minKey in MinExcludeOrInclude]: number;
  [maxKey in MaxExcludeOrInclude]: number; // yes mistake over here =)
};

CodePudding user response:

One solution could look like this:

type MinExcludeOrInclude = DiapasonBorders.MinInclude | DiapasonBorders.MinExclude;
type MaxExcludeOrInclude = DiapasonBorders.MaxInclude | DiapasonBorders.MaxExclude;

export type DiapasonBordersSetting = {
  [K in MinExcludeOrInclude]: {
    [K2 in MaxExcludeOrInclude]: Record<K | K2, number>
  }[MaxExcludeOrInclude]
}[MinExcludeOrInclude] extends infer O ? { [K in keyof O]: O[K] } : never

By mapping over MinExcludeOrInclude and MaxExcludeOrInclude we can construct a Record for each combination.

Playground


You might also be interested in a way of defining MinExcludeOrInclude without manually listing every member.

type MinExcludeOrInclude = GetByPrefix<"min">
type MaxExcludeOrInclude = GetByPrefix<"max">

export type GetByPrefix<P extends string> = {
  [K in DiapasonBorders as K extends `${P}${string}` ? K : never]: K
} extends infer O ? O[keyof O] : never
  • Related