Class type check in TypeScript
Asked Answered
O

5

496

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.

Oribel answered 8/10, 2012 at 20:47 Comment(0)
C
603

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:

Cirilla answered 8/10, 2012 at 20:54 Comment(0)
S
140

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

Setscrew answered 21/11, 2016 at 10:42 Comment(6)
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.Oribel
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.Fremont
this is also called "User Defined Type Guards", see basarat.gitbooks.io/typescript/content/docs/types/…Inspection
@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).Yulandayule
You may want to consider using (pet as Fish) since the tslinter will complain about (<Fish>pet). See tslint docCubage
User Defined Type Guards link: basarat.gitbook.io/typescript/type-system/… (Julian's comment's link -> 404)Kwapong
P
27

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

Preclinical answered 20/4, 2020 at 8:47 Comment(0)
A
16

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;
}
Aikido answered 23/3, 2022 at 17:25 Comment(1)
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 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.Fatuous
C
4

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 =>
   'swim' in pet;

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

Council answered 2/12, 2022 at 19:46 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.