Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

TypeScript type guards and "only refers to a type, but is being used as a value here."

Tags:

typescript

I'm using Typescript 3.2.2 and unable to achieve the most basic implementation of type guards:

interface Bird {
    fly(): boolean;
}

interface Fish {
    swim(): boolean;
}

function swimIfYouCan(x: Fish | Bird) {
    if ((<Fish>x).swim) {
        return true
    }
}

This produces Error:(50, 11) TS2693: 'Fish' only refers to a type, but is being used as a value here. in WebStorm and SyntaxError: /Users/sea-kent/git/docket-management/webapp/src/App.tsx: Unexpected token (51:8) from yarn. Is there a configuration needed to enable this syntax?

like image 376
Aaron Kent Avatar asked Sep 06 '25 22:09

Aaron Kent


2 Answers

There are three different approaches possible that come to my mind for your problem.

  1. If you want to cast it and directly use it you have to use the as operator (as mentioned by @jonrsharpe in the comments), so for example (x as Fish).swim

  2. use the in operator to check if it is available, e.g. if ('swim' in x)

  3. Last but not least (and for this case in my opinion the best case), simply do an instance of check to check what instance you've got: if (x instance of Fish)

Edit: Didn't read the question well enough, you can't check for interfaces in runtime. But there is no harm in creating a class on top of the interface

like image 145
Nicolas Gehlert Avatar answered Sep 08 '25 12:09

Nicolas Gehlert


The recommended way to do pattern matching by checking the existence of a property is the in operator:

interface Bird {
    fly(): boolean;
}

interface Fish {
    swim(): boolean;
}

function move(x: Fish | Bird) {
  if ("swim" in x) {
    return x.swim();
  } else {
    return x.fly();
  }
}

By using the in operator you can avoid the assertion.

like image 35
Remo H. Jansen Avatar answered Sep 08 '25 10:09

Remo H. Jansen