Home > database >  Typescript enum encapsulating a boolean value per enum instance
Typescript enum encapsulating a boolean value per enum instance

Time:01-05

In Typescript, what is the idiomatic way to have a boolean value assigned for each enum instance?

Say I have an enum for various error codes. For each of the error codes, I have a boolean stating if the error must be exposed to the end user or not. In Java, I would do like,

enum MyError {
    ERROR1(true),
    ERROR2(false),
    ERROR3(false);

    private boolean expose;

    public boolean shouldExpose() {
        return expose;
    }

    MyError(boolean expose) {
        this.expose = expose;
    }
}

Here, the boolean info (whether the error must be exposed to user or not) is encapsulated within the enum itself.

 MyError myError = MyError.ERROR1;
 System.out.println(myError.shouldExpose()); //true

How can I do this in Typescript as TS doesn't allow boolean values in enums? Should I use a class or a type here?

The goal is to have the boolean information contained in the enum/class/type. Hence, I don't want to create a wrapper type like

{
    error: MyError
    expose: boolean
}

as it can lead to wrong configuration/mappings (it becomes possible to have MyError.ERROR1 with expose as false or vice-versa for other errors).

CodePudding user response:

You wouldn't try to fit this information about the errors in the enumeration itself. The enumeration is simply for listing (well, enumerating) the errors. Their exposeness should be saved in a mapping between the error and the answer to the "is it exposed?" question.

// values don't matter; you can also skip them if you don't care for them
enum Error {
  Fatal = 1,
  Disk = 2,
  NoInternet = 3,
}

const IS_EXPOSED: Readonly<Record<Error, boolean>> = {
  [Error.Fatal]: false,
  [Error.Disk]: true,
  [Error.NoInternet]: true,
}

TypeScript's type system will throw an error if you miss an enumeration in the IS_EXPOSED object, so it's completely type-safe.

CodePudding user response:

You might want to give up on actual enums and instead make your own set of constants. It's more verbose but it might meet your needs.

const MyError = {
  error1: {
    name: 'ERROR1',
    expose: true
  },
  error2: {
    name: 'ERROR2',
    expose: false
  },
  error3: {
    name: 'ERROR3',
    expose: false
  }
} as const;

type MyError = typeof MyError[keyof typeof MyError]


function x(err: MyError) {
  console.log(err);
}

x(MyError.error1);
x({name: 'ERROR1', expose: true});
x({name: 'ERROR1', expose: false}); // EXPECTED ERROR

function getError(): MyError {
  return MyError.error1;
}

var e: MyError = getError();
console.log(MyError.error1 == e);  // true
console.log(MyError.error2 == e);  // false

Playground link

CodePudding user response:

If you do not care about the enumerical order then you could leverage numeric enums e.g.

enum MyError  {
  ERROR1 = 1,
  ERROR2 = 0,
  ERROR3 = 0,
}

console.log(MyError.ERROR1); // 1 == true
console.log(MyError.ERROR2); // 0 == false
console.log(MyError.ERROR3); // 0 == false

console.log(Boolean(MyError.ERROR1)); // true
console.log(Boolean(MyError.ERROR2)); // false
console.log(Boolean(MyError.ERROR3)); // false

EDIT:

You could use namespace merging e.g.

namespace MyError {
    export function shouldExpose(error:MyError) {
        return Boolean(error);
    }
}

console.log(MyError.shouldExpose(MyError.ERROR1)); // true

CodePudding user response:

You can create a class which extends the native Error class:

TS Playground

enum ErrorVariant {
  ERROR1 = 1,
  ERROR2 = 2,
  ERROR3 = 3,
}

class MyError<T extends boolean> extends Error {
  constructor (
    readonly variant: ErrorVariant,
    private readonly expose: T,
    message?: string,
  ) {
    super(message);
  }

  shouldExpose (): T {
    return this.expose;
  }
}

const myError1 = new MyError(ErrorVariant.ERROR1, false, 'Uh oh');
myError1.shouldExpose() // false
myError1.variant // ErrorVariant => 1

const myError2 = new MyError(ErrorVariant.ERROR2, true, 'Uh oh');
myError2.shouldExpose() // true
myError2.variant // ErrorVariant => 2
myError2.message // string

CodePudding user response:

It might be a good idea to use bitmask for this purpose:

enum CustomErrors {
    Error1 = 1 << 0,
    Error2 = 1 << 1,
    Error3 = 1 << 2
}

const error_1 = 0b001
const error_1_AND_2 = 0b011
const error_1_AND_3 = 0b101
const error_3 = 0b101

const isError1 = CustomErrors.Error1 & error_1 // 1, true
const isError2 = CustomErrors.Error2 & error_1 // 0, false
const isError1_2 = CustomErrors.Error2 & error_1_AND_2 // 2, true
const isError1_2_ = CustomErrors.Error3 & error_3 // 4, true

Playground

  •  Tags:  
  • Related