Ask Your Question
4

How can compound enums be dynamically remapped in Typescript while ensuring type safety?

asked 2022-04-06 11:00:00 +0000

nofretete gravatar image

edit retag flag offensive close merge delete

1 Answer

Sort by ยป oldest newest most voted
0

answered 2022-11-01 09:00:00 +0000

lalupa gravatar image

There are a few ways to dynamically remap compound enums in Typescript while ensuring type safety:

  1. Using a mapping object:
  • Define a mapping object that maps the original enum values to the new enum values.
  • Create a function that takes an original enum value as input and returns the mapped enum value.
  • Use the function to dynamically remap the enum values while ensuring type safety.

Example:

enum OriginalEnum {
  A = 'A',
  B = 'B',
  C = 'C',
}

enum MappedEnum {
  X = 'X',
  Y = 'Y',
  Z = 'Z',
}

const mapping = {
  [OriginalEnum.A]: MappedEnum.X,
  [OriginalEnum.B]: MappedEnum.Y,
  [OriginalEnum.C]: MappedEnum.Z,
};

function mapEnum(originalValue: OriginalEnum): MappedEnum {
  return mapping[originalValue];
}

const originalValue = OriginalEnum.A;
const mappedValue = mapEnum(originalValue); // MappedEnum.X

// Type safety:
// mapEnum(OriginalEnum.A) // MappedEnum.X
// mapEnum(OriginalEnum.B) // MappedEnum.Y
// mapEnum(OriginalEnum.C) // MappedEnum.Z
// mapEnum('invalid') // compile error
  1. Using object-oriented programming:
  • Define a base enum class that provides a method to get the enum value name.
  • Define subclass enums that extend the base enum class and provide their own mappings.
  • Use the subclass enums to dynamically remap the enum values while ensuring type safety.

Example:

abstract class BaseEnum {
  abstract getName(): string;
}

class OriginalEnumValue extends BaseEnum {
  private readonly _name: string;

  constructor(name: string) {
    super();
    this._name = name;
  }

  getName(): string {
    return this._name;
  }
}

class MappedEnumValue extends BaseEnum {
  private readonly _name: string;

  constructor(name: string) {
    super();
    this._name = name;
  }

  getName(): string {
    return this._name;
  }
}

class OriginalEnum extends BaseEnum {
  static readonly A = new OriginalEnumValue('A');
  static readonly B = new OriginalEnumValue('B');
  static readonly C = new OriginalEnumValue('C');

  static mapTo(mappedEnum: typeof MappedEnum): MappedEnumValue {
    switch (this) {
      case OriginalEnum.A:
        return mappedEnum.X;
      case OriginalEnum.B:
        return mappedEnum.Y;
      case OriginalEnum.C:
        return mappedEnum.Z;
      default:
        throw new Error(`Invalid OriginalEnum value: ${this.getName()}`);
    }
  }

  getName(): string {
    return this.constructor.name;
  }
}

class MappedEnum extends BaseEnum {
  static readonly X = new MappedEnumValue('X');
  static readonly Y = new MappedEnumValue('Y');
  static readonly Z = new MappedEnumValue('Z');

  getName(): string {
    return this.constructor.name;
  }
}

const originalValue = OriginalEnum.A;
const mappedValue = OriginalEnum.mapTo(MappedEnum); // MappedEnum.X

// Type safety:
// OriginalEnum.A.mapTo(MappedEnum) // MappedEnum.X
// OriginalEnum.B.mapTo(MappedEnum) // MappedEnum.Y
// OriginalEnum.C.mapTo(MappedEnum) // MappedEnum.Z
// OriginalEnum.A.mapTo(OriginalEnum) // compile error
// OriginalEnum.D.mapTo(MappedEnum) // runtime error
edit flag offensive delete link more

Your Answer

Please start posting anonymously - your entry will be published after you log in or create a new account. This space is reserved only for answers. If you would like to engage in a discussion, please instead post a comment under the question or an answer that you would like to discuss

Add Answer


Question Tools

Stats

Asked: 2022-04-06 11:00:00 +0000

Seen: 12 times

Last updated: Nov 01 '22