Testing if an interface is implemented at runtime

Topics: General, Language Specification
Nov 1, 2012 at 1:07 AM

According the language specification (7.2 Dynamic Type Checks), I think it is simple to generate JavaScript code for dynamically testing whether an object implements a particular interface. We just need to change the code the "instanceof" operator emits, if an interface as the right argument specified. For example:

module a.b.c
{
	export interface IFoo{
		foo():void;
		bar():void;
	}
}

// somethere in code
alert(obj instanceof a.b.c.IFoo);

could be translated into:

var a;
(function (a) {
    (function (b) {
        (function (c) {
            var IFoo = {
				_instanceof: function(arg){
					return typeof(arg) !== "undefined" && arg !== null && typeof(arg.foo) === "function" && typeof(arg.bar) === "function");
				}
			}
            c.IFoo = IFoo;            
        })(b.c || (b.c = {}));
        var c = b.c;

    })(a.b || (a.b = {}));
    var b = a.b;

})(a || (a = {}));

// somethere in code
alert(a.b.c.IFoo._instanceof(obj));

Coordinator
Nov 1, 2012 at 4:25 PM

This will likely not happen.  Generally, it's easier for the user to opt to add a tag to their objects telling the system what the object type is (or what interface(s) it implements).  Interfaces are a purely structural contract in TypeScript, the name they have is just an easy way to refer to them.  To check if an object met an interface at runtime would require reflecting through the whole object's structure (and in some cases this may not be possible to check the whole structure, eg function types or recursive types).

 

Nov 2, 2012 at 2:29 PM

In the interview with Anders Hejlsberg and Lars Bak on Typescript here, Anders mentions that adding reflection to JavaScript would be a very expensive operation, both in resource usage and time.

However, Ross Harmes and Dustin Diaz in their book "Pro JavaScript Design Patterns" - propose a simple JavaScript run-time type-checking mechanism for testing whether an object implements a particular interface.

I have blogged about how to implement this pattern in TypeScript, and how it can be used to build a simple IoC Container here.

Have fun,

Nov 7, 2012 at 12:25 PM
Edited Nov 7, 2012 at 12:44 PM

Here's a simpler technique for testing if a class implements an interface at run time.  It's obviously a little brittle because it requires you a) manually define a name for each interface, and b) then tag each object with the interfaces it implements.  But it will in fact work if you absolutely need this capability and it will be more performant then checking an object to see if it implements all of the individual members of an interface.  It also supports optional members and interface inheritance so it covers all of the bases.

 

// Base interface for all named interfaces
interface IBase {
	__implements: string;
}
var IBaseName = 'IBase,';

function doesImplement(obj: IBase, type: string): bool {
	return (obj && obj.__implements && obj.__implements.indexOf(type) >= 0);
}

// App specific interfaces
interface IFoo extends IBase {
	method1(): void;
	method2?(): void;
}
var IFooName = IBaseName + 'IFoo,';

interface IBar extends IBase {
	method3(): void;
}
var IBarName = IBaseName + 'IBar,';

class Bar implements IFoo, IBar {
	public __implements = IFooName + IBarName;
	
	method1(): void { }
	method3(): void { }
}

// Runtime checks
var x = new Bar();
alert('Implements IFoo: ' + doesImplement(x, IFooName));
alert('Implements IBase: ' + doesImplement(x, IBaseName));