Search code examples
typescriptenumsassert

How to transform TS asserts condition in handy function?


I'm using asserts condition and have a code like this

enum Types { a = "a", b = "b", c = "c" }

type Entity = { type: Types };

assert(condition: any): asserts condition {
  if(!condition) throw new Error();
}

function abc(entity: Entity) {
  assert(entity.type === Types.a || entity.type === Types.b);
  ...
}

function def(entity: Entity) {
  assert(entity.type === Types.b || entity.type === Types.c);
  ...
}

function ghi(entity: Entity) {
  assert(entity.type === Types.c);
  ...
}

Is it possible to make compact generic assertion function to use like this and get the same assertion type checks?

assertType(entity, [Types.a, Types.b]);

Solution

  • Answers to this question gave me an idea of solution.

    function checkObjectType<
        T extends { type: unknown }, 
        X, 
        Y = never, 
        Z = never
    >(obj: T, types: readonly [X, Y?, Z?]): obj is S & { type: X | Y | Z } {
        return types.some((type) => type === obj.type;
    }
    
    
    // Then I can write code like this.
    function abc(entity: Entity) {
      assert(checkObjectType(entity, [Types.a, Types.b] as const));
      ...
      // in Runtime we check assertion and get only types a and b here
      // in Compiletime TS knows that only types a and b can be expected here
    }