Javascript – Interface type check with Typescript

interfacejavascripttypescript

This question is the direct analogon to Class type check with TypeScript

I need to find out at runtime if a variable of type any implements an interface. Here's my code:

interface A{
    member:string;
}

var a:any={member:"foobar"};

if(a instanceof A) alert(a.member);

If you enter this code in the typescript playground, the last line will be marked as an error, "The name A does not exist in the current scope". But that isn't true, the name does exist in the current scope. I can even change the variable declaration to var a:A={member:"foobar"}; without complaints from the editor. After browsing the web and finding the other question on SO I changed the interface to a class but then I can't use object literals to create instances.

I wondered how the type A could vanish like that but a look at the generated javascript explains the problem:

var a = {
    member: "foobar"
};
if(a instanceof A) {
    alert(a.member);
}

There is no representation of A as an interface, therefore no runtime type checks are possible.

I understand that javascript as a dynamic language has no concept of interfaces. Is there any way to type check for interfaces?

The typescript playground's autocompletion reveals that typescript even offers a method implements. How can I use it ?

Best Answer

You can achieve what you want without the instanceof keyword as you can write custom type guards now:

interface A{
    member:string;
}

function instanceOfA(object: any): object is A {
    return 'member' in object;
}

var a:any={member:"foobar"};

if (instanceOfA(a)) {
    alert(a.member);
}

Lots of Members

If you need to check a lot of members to determine whether an object matches your type, you could instead add a discriminator. The below is the most basic example, and requires you to manage your own discriminators... you'd need to get deeper into the patterns to ensure you avoid duplicate discriminators.

interface A{
    discriminator: 'I-AM-A';
    member:string;
}

function instanceOfA(object: any): object is A {
    return object.discriminator === 'I-AM-A';
}

var a:any = {discriminator: 'I-AM-A', member:"foobar"};

if (instanceOfA(a)) {
    alert(a.member);
}