Search code examples
typescriptdesign-patternslanguage-featurestype-alias

How to type check a binary type alias in Typescript


I would like to depend a condition on the given type of an argument, but since all possible arguments are the same binary type (number), I look for a way to create some kind of a type alias, that can be checked for.

This is the initial idea, that doesn't work, because typescript is compiled into javascript and thus bonus will always be the javascript type number.

    type Percentage = number;

    class Foo {
      applyBonus(bonus: Percentage | number) {
        if (typeof bonus === 'Percentage') {
          console.log('Percent');
        } else {
          // it's always number, because at execution time we're in javascript land here
          console.log('number'); 
        } 
      }
    }

    let bar = new Foo();
    bar.applyBonus(5);
    bar.applyBonus(6 as Percentage);

This question is mainly focused on the possibilities of the typescript language, and if this can be solved with typescript features. It would be easily possible to use an object like {value:6,type:'percent'} instead of a binary type number.


Solution

  • Typescript doesn't type based on the names of things, but the structure of thing. You can name a number something else, but it's still a number. Percentage here is just an alias.

    A better way to do something like this would be to create an interface with a unique shape that you could easily identify at runtime.

    interface Percentage { percentage: number }
    
    class Foo {
       applyBonus(bonus: Percentage | number) {
          if (typeof bonus === 'object') {
             console.log('Percent', bonus.percentage);
          } else {
             console.log('number', bonus); 
          } 
       }
    }
    
    new Foo().applyBonus(123)
    new Foo().applyBonus({ percentage: 456 })
    

    Playground


    Alternatively (I don't recommend this, but is interesting academically), you could subclass Number and use that.

    class Percentage extends Number { }
    
    class Foo {
       applyBonus(bonus: Percentage | number) {
          if (bonus instanceof Percentage) {
             console.log('Percent', bonus);
          } else {
             console.log('number', bonus); 
          } 
       }
    }
    
    new Foo().applyBonus(123)
    new Foo().applyBonus(new Percentage(456))
    

    But really, I would question your need for this. I'm not sure what you are trying to accomplish here, but there is probably a simpler way.