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.
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