Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Check if variable belongs to custom type in Typescript

I'm trying to check whether a variable belongs to a certain type or not.

Code:

type GeneralType = SubTypeA | SubTypeB;
type SubTypeA = 'type1' | 'type2';
type SubTypeB = 'type3' | 'type4';

function someFunction(arg1: GeneralType) {
  if (arg1 instanceof SubTypeA) {
    // Do something
  }
  // Continue function
  return arg1;
}

Of course this code fails in line 6 because instanceof is not usable for types. Is there an alternative option I could use without needing to check explicitly every posible value for SubTypeA?

like image 232
Martín De la Fuente Avatar asked Jan 11 '19 13:01

Martín De la Fuente


2 Answers

As mentioned in the comments, it seems there's no strightforward method to achieve this.

Finally, the most elegant way I found to do it is using Type Guards as follows:

type GeneralType = SubTypeA | SubTypeB;
type SubTypeA = 'type1' | 'type2';
type SubTypeB = 'type3' | 'type4';

function someFunction(arg1: GeneralType) {
  if (isSubTypeA(arg1)) {
    // Do something
  }
  // Continue function
}

function isSubTypeA(arg: GeneralType): arg is SubTypeA {
  return ['type1', 'type2'].some(element => element === arg);
}

A more detailed explanation can be found here.

like image 97
Martín De la Fuente Avatar answered Oct 19 '22 18:10

Martín De la Fuente


Type guards are commonly used to discriminate unions. There are more ways this can be done:

  1. Use the switch statement.
  2. Use enums.

The switch statement

This method is easy but can become cumbersome if your unions are big.

function someFunction(arg1: GeneralType) {
  switch(arg1) {
      case 'type1':
      case 'type2':
        return /* */  
      default:
        /* ... */
  }
}

someFunction('type1');

Enums

The disadvantage here is that it doesn't work with string enums, only the regular ones.

enum SubTypeA {
    type1,
    type2,
}

enum SubTypeB {
    type3,
    type4,
}

type GeneralType = SubTypeA | SubTypeB;

function someFunction(arg1: GeneralType) {
    if (arg1 in SubTypeA) {
        /* ... */
    }
}

someFunction(SubTypeA.Type1);

As you can see, writing a type guard requires more work up front, but type guards don't have the limitations other methods have. In addition to that, they are just functions, so they can be reused. You made a good choice.

like image 1
Karol Majewski Avatar answered Oct 19 '22 19:10

Karol Majewski