467

In ActionScript, it is possible to check the type at run-time using the is operator:

var mySprite:Sprite = new Sprite(); 
trace(mySprite is Sprite); // true 
trace(mySprite is DisplayObject);// true 
trace(mySprite is IEventDispatcher); // true

Is it possible to detect if a variable (extends or) is a certain class or interface with TypeScript?

I couldn't find anything about it in the language specs. It should be there when working with classes/interfaces.

Mark Knol
  • 9,663
  • 3
  • 29
  • 44

5 Answers5

576

4.19.4 The instanceof operator

The instanceof operator requires the left operand to be of type Any, an object type, or a type parameter type, and the right operand to be of type Any or a subtype of the 'Function' interface type. The result is always of the Boolean primitive type.

So you could use

mySprite instanceof Sprite;

Note that this operator is also in ActionScript but it shouldn't be used there anymore:

The is operator, which is new for ActionScript 3.0, allows you to test whether a variable or expression is a member of a given data type. In previous versions of ActionScript, the instanceof operator provided this functionality, but in ActionScript 3.0 the instanceof operator should not be used to test for data type membership. The is operator should be used instead of the instanceof operator for manual type checking, because the expression x instanceof y merely checks the prototype chain of x for the existence of y (and in ActionScript 3.0, the prototype chain does not provide a complete picture of the inheritance hierarchy).

TypeScript's instanceof shares the same problems. As it is a language which is still in its development I recommend you to state a proposal of such facility.

See also:

Zeta
  • 103,620
  • 13
  • 194
  • 236
128

TypeScript have a way of validating the type of a variable in runtime. You can add a validating function that returns a type predicate. So you can call this function inside an if statement, and be sure that all the code inside that block is safe to use as the type you think it is.

Example from the TypeScript docs:

function isFish(pet: Fish | Bird): pet is Fish {
   return (<Fish>pet).swim !== undefined;
}

// Both calls to 'swim' and 'fly' are now okay.
if (isFish(pet)) {
  pet.swim();
}
else {
  pet.fly();
}

See more at: https://www.typescriptlang.org/docs/handbook/advanced-types.html

Gilad S
  • 1,753
  • 1
  • 13
  • 14
  • 75
    This is not runtime typechecking, it's just checking if a object has a certain property. This may be nice for union types so works for this specific case, but its not really doable to create a "isThingy" for everything like this. Also if both fish and bird could swim you're doomed. I'm glad I'm using Haxe which has a reliable type checking so you can do `Std.is(pet, Fish)`, which works on types, interfaces etc. – Mark Knol Nov 21 '16 at 14:58
  • 5
    I found this answer helpful, but I think you could tweak it to be a little more precise. The `isFish` itself is the predicate that is created, and its body doesn't have to be a one-liner predicate. The advantage of this is that the compiler understands at compile time the appropriate possible functions, but your code inside `isFish` is executed at runtime. You could even have the guard contain an `instanceof` statement, e.g. `return pet instanceof Fish` (assuming it's a class and not an interface), but this would be unnecessary since the compiler understands `instanceof` directly. –  Apr 19 '17 at 19:42
  • 4
    this is also called "User Defined Type Guards", see https://basarat.gitbooks.io/typescript/content/docs/types/typeGuard.html – Julian Jun 15 '17 at 11:21
  • 1
    @MarkKnol it actually is runtime checking but brings as to typescript the ability to understand the inferred type as well (meaning: you can trust me this will be type X or Y because I will test it at runtime). – Flavien Volken Apr 11 '18 at 08:22
  • 6
    You may want to consider using `(pet as Fish)` since the tslinter will complain about `(pet)`. See [tslint doc](https://palantir.github.io/tslint/rules/no-angle-bracket-type-assertion/) – Bryan Apr 17 '18 at 17:13
  • User Defined Type Guards link: https://basarat.gitbook.io/typescript/type-system/typeguard#user-defined-type-guards (Julian's comment's link -> 404) – Fullchee Zhang Aug 08 '22 at 19:36
25

You can use the instanceof operator for this. From MDN:

The instanceof operator tests whether the prototype property of a constructor appears anywhere in the prototype chain of an object.

If you don't know what prototypes and prototype chains are I highly recommend looking it up. Also here is a JS (TS works similar in this respect) example which might clarify the concept:

    class Animal {
        name;
    
        constructor(name) {
            this.name = name;
        }
    }
    
    const animal = new Animal('fluffy');
    
    // true because Animal in on the prototype chain of animal
    console.log(animal instanceof Animal); // true
    // Proof that Animal is on the prototype chain
    console.log(Object.getPrototypeOf(animal) === Animal.prototype); // true
    
    // true because Object in on the prototype chain of animal
    console.log(animal instanceof Object); 
    // Proof that Object is on the prototype chain
    console.log(Object.getPrototypeOf(Animal.prototype) === Object.prototype); // true
    
    console.log(animal instanceof Function); // false, Function not on prototype chain
    
    

The prototype chain in this example is:

animal > Animal.prototype > Object.prototype

Willem van der Veen
  • 33,665
  • 16
  • 190
  • 155
15

You have two types of checks

by ex, the isString check can be performed like this:

function isString(value) {
    return typeof value === 'string' || value instanceof String;
}
serge
  • 13,940
  • 35
  • 121
  • 205
  • If you are going to use a separate function for codified type checks, it would be best to also tell the compiler about this being a [type predicate](https://www.typescriptlang.org/docs/handbook/2/narrowing.html#using-type-predicates) so that calling the function subsequently narrows the type of the argument: `function isString(value): value is string { return typeof value === 'string' || value instanceof String; } const x: any = "im a string!"; if (isString(x)) console.log(x.toUpperCase());` Note that the return type is `value is string`. – j1mbl3s Mar 23 '22 at 17:38
2

Although late and already some good answers exists. The proposed solution from @Gilad has the flaw if the assigned content swim exists as Type but the Value is set to undefined. A more robust check would be:

export const isFish= (pet: Fish | Bird): pet is Fish =>
   Object.keys(pet).includes('swim');

This solution wouldn't be dependent on the value of swim!

LeO
  • 4,238
  • 4
  • 48
  • 88